Kubernetes Ingress giúp phân luồng truy cập từ bên ngoài cluster Kubernetes đến các service bên trong cluster một cách linh hoạt. Để làm việc này, ta kết hợp cài đặt Nginx Ingress Resource (định nghĩa các rule phân luồng lưu lượng HTTP và HTTPS đến các service Kubernetes) và Ingress Controller (áp dụng các rule đó bằng cách cân bằng lưu lượng và dẫn chúng đến các service backend phù hợp).
Các Ingress Controller phổ biến bao gồm Nginx, Contour, HAProxy và Traefik. Ingress là giải pháp thay thế hiệu quả và linh hoạt hơn so với việc thiết lập nhiều service loại LoadBalancer vì mỗi service loại này thường yêu cầu một load balancer chuyên dụng riêng.
Trong bài này, chúng ta sẽ thiết lập Nginx Ingress Controller (phần mềm do tổ chức Kubernetes phát triển) và tạo một số Ingress Resource để định tuyến lưu lượng đến một vài service backend giả lập. Sau khi thiết lập xong Ingress, chúng ta sẽ cài đặt cert-manager vào cluster để quản lý và cung cấp chứng chỉ TLS nhằm mã hóa lưu lượng HTTP đến Ingress.
Những điều kiện tiên quyết
Trước khi bắt đầu, bạn cần cài đặt sẵn các thành phần sau:
- Một cluster Kubernetes phiên bản 1.15 trở lên đã bật tính năng quản lý truy cập theo vai trò (RBAC). Bài này sẽ dùng một cluster DigitalOcean Kubernetes, nhưng bạn có thể tạo cluster bằng các phương pháp khác.
- Công cụ kubectl đã được cấu hình nó để kết nối với cluster. Bạn có thể tìm hiểu thêm về cách cài đặt kubectl ở trang tài liệu chính thức.
- Một tên miền và các bản ghi DNS A để trỏ đến DigitalOcean Load Balancer được Ingress sử dụng.
- Công cụ wget. Bạn có thể cài đặt nó bằng package manager của hệ điều hành.
Sau khi đã thiết lập xong các thành phần trên, hãy làm theo các bước sau:
Bước 1: Cài đặt service backend giả lập
Trước khi triển khai Ingress Controller, chúng ta sẽ tạo và triển khai hai service echo giả lập để dẫn lưu lượng truy cập bên ngoài bằng Ingress. Các service echo này sẽ chạy container web server hashicorp/http-echo và trả về một trang chuỗi text được đặt khi web server khởi chạy.
Tham khảo GitHub của http-echo và tài liệu Services của Kubernetes để tìm hiểu thêm về hai công cụ này.
Trên máy local của bạn, tạo một file có tên echo1.yaml bằng nano hoặc bất kì editor nào khác:
nano echo1.yaml
Điền manifest cho Service và Deployment như sau đây:
apiVersion: v1
kind: Service
metadata:
name: echo1
spec:
ports:
- port: 80
targetPort: 5678
selector:
app: echo1
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: echo1
spec:
selector:
matchLabels:
app: echo1
replicas: 2
template:
metadata:
labels:
app: echo1
spec:
containers:
- name: echo1
image: hashicorp/http-echo
args:
- "-text=echo1"
ports:
- containerPort: 5678
Ở đây, ta định nghĩa một Service tên là echo1. Nó định tuyến lưu lượng truy cập đến các pod có label selector là app: echo1. Service này chấp nhận lưu lượng TCP trên cổng 80 và dẫn nó đến cổng 5678 (cổng mặc định của http-echo).
Sau đó, chúng ta định nghĩa một Deployment (cũng có tên là echo1) để quản lý các pod có label selector app: echo1. Chúng ta chỉ định Deployment sẽ có 2 pod nhân bản (replica) và các pod này sẽ khởi động một container tên là echo1 chạy image hashicorp/http-echo.
Chúng ta truyền vào tham số text và đặt giá trị là echo1, để web server http-echo trả về echo1. Cuối cùng, chúng ta mở cổng 5678 trên container của pod.
Sau khi đã chỉnh sửa xong với manifest Service và Deployment giả lập, chúng ta lưu và đóng file này.
Sau đó, tạo các resource Kubernetes bằng lệnh kubectl apply với cờ -f để chỉ định file chúng ta vừa lưu làm tham số:
kubectl apply -f echo1.yaml
Bạn sẽ thấy output sau:
service/echo1 created
deployment.apps/echo1 created
Xác minh service đã khởi động đúng bằng cách kiểm tra xem nó có ClusterIP (IP nội bộ mà service được expose ra) hay không:
kubectl get svc echo1
Bạn sẽ thấy output sau:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
echo1 ClusterIP 10.245.222.129 <none> 80/TCP 60s
Ta thấy Service echo1 hiện đã có thể dùng trong nội bộ tại địa chỉ 10.245.222.129 trên cổng 80. Nó sẽ chuyển tiếp lưu lượng truy cập đến containerPort 5678 trên các pod mà nó chọn.
Sau khi service echo1 đã hoạt động, hãy lặp lại quy trình này cho Service echo2.
Tạo một file có tên echo2.yaml với nội dung sau:
apiVersion: v1
kind: Service
metadata:
name: echo2
spec:
ports:
- port: 80
targetPort: 5678
selector:
app: echo2
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: echo2
spec:
selector:
matchLabels:
app: echo2
replicas: 1
template:
metadata:
labels:
app: echo2
spec:
containers:
- name: echo2
image: hashicorp/http-echo
args:
- "-text=echo2"
ports:
- containerPort: 5678
Ta sử dụng manifest Service và Deployment tương tự như trên, nhưng đặt tên và gán lại label cho chúng là echo2. Ngoài ra, chúng ta chỉ tạo 1 replica pod để có khác biệt. Đảm bảo phải set tham số text thành echo2 để web server trả về chuỗi này.
Lưu và đóng file, sau đó tạo các resource Kubernetes bằng kubectl:
kubectl apply -f echo2.yaml
Bạn sẽ thấy output sau:
service/echo2 created
deployment.apps/echo2 created
Một lần nữa, xác minh service đã hoạt động:
kubectl get svc
Bạn sẽ thấy cả hai service echo1 và echo2 cùng với ClusterIP của chúng:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
echo1 ClusterIP 10.245.222.129 <none> 80/TCP 6m6s
echo2 ClusterIP 10.245.128.224 <none> 80/TCP 6m3s
kubernetes ClusterIP 10.245.0.1 <none> 443/TCP 4d21h
Khi các web service echo giả lập đã hoạt động, chúng ta có thể chuyển sang triển khai Nginx Ingress Controller.
Bước 2: Thiết lập Kubernetes Nginx Ingress Controller
Trong bước này, chúng ta sẽ dùng phiên bản v1.1.1 của Nginx Ingress Controller. Lưu ý rằng có nhiều phiên bản Nginx Ingress Controller khác nhau. Bài này dùng bản do cộng đồng Kubernetes phát triển, nhưng ngoài ra còn có kubernetes-ingress của công ty Nginx.
Nginx Ingress Controller bao gồm một pod chạy máy chủ web Nginx và theo dõi Kubernetes control plane để phát hiện các đối tượng Ingress Resource mới tạo hay vừa được cập nhật. Một Ingress Resource về cơ bản là một danh sách các rule định tuyến truy cập cho các service backend.
Ví dụ, một rule Ingress có thể chỉ định rằng lưu lượng HTTP đến đường dẫn /web1 sẽ được chuyển hướng đến web server backend web1. Với Ingress Resource, bạn cũng có thể thực hiện định tuyến dựa trên host. Ví dụ, chuyển các request đến web1.your_domain.com tới service Kubernetes backend web1.
Trong bài này, chúng ta đang triển khai Ingress Controller trên một Kubernetes cluster trên DigitalOcean. Vì thế Controller sẽ tạo ra một service loại LoadBalancer có nhiệm vụ cấp phát một load balancer của DigitalOcean mà toàn bộ lưu lượng truy cập bên ngoài sẽ được chuyển đến. Load balancer này sẽ định tuyến lưu lượng truy cập bên ngoài đến pod Ingress Controller đang chạy Nginx, sau đó Nginx sẽ chuyển tiếp lưu lượng truy cập đến các service backend phù hợp.
Chúng ta sẽ bắt đầu bằng cách tạo các resource Kubernetes cho Nginx Ingress Controller. Các resource này bao gồm ConfigMap chứa cấu hình của Controller, các role RBAC để cấp cho controller quyền truy cập vào Kubernetes API, và Deployment Ingress Controller thực tế sử dụng image Nginx Ingress Controller phiên bản v1.1.1. Để xem danh sách đầy đủ các resource bắt buộc này, hãy tham khảo manifest từ GitHub repo của Kubernetes Nginx Ingress Controller.
Lưu ý: Trong bài hướng dẫn này, chúng ta đang làm theo hướng dẫn chính thức cho DigitalOcean. Bạn nên chọn file manifest phù hợp tùy thuộc vào nhà cung cấp Kubernetes của mình.
Để tạo các resource, sử dụng lệnh kubectl apply và cờ -f để chỉ định file manifest được lưu trữ trên GitHub:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.1.1/deploy/static/provider/do/deploy.yaml
Chúng ta sử dụng apply ở đây để trong tương lai ta có thể cập nhật các thay đổi cho các đối tượng Ingress Controller mà không cần ghi đè chúng hoàn toàn. Để tìm hiểu thêm về lệnh apply, hãy tham khảo mục Managing Resources từ tài liệu chính thức của Kubernetes.
Bạn sẽ thấy output sau:
namespace/ingress-nginx created
serviceaccount/ingress-nginx created
configmap/ingress-nginx-controller created
clusterrole.rbac.authorization.k8s.io/ingress-nginx created
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx created
role.rbac.authorization.k8s.io/ingress-nginx created
rolebinding.rbac.authorization.k8s.io/ingress-nginx created
service/ingress-nginx-controller-admission created
service/ingress-nginx-controller created
deployment.apps/ingress-nginx-controller created
validatingwebhookconfiguration.admissionregistration.k8s.io/ingress-nginx-admission created
clusterrole.rbac.authorization.k8s.io/ingress-nginx-admission created
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created
job.batch/ingress-nginx-admission-create created
job.batch/ingress-nginx-admission-patch created
role.rbac.authorization.k8s.io/ingress-nginx-admission created
rolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created
serviceaccount/ingress-nginx-admission created
Output này cũng cho ta một bản tóm tắt về tất cả các đối tượng Ingress Controller được tạo từ manifest deploy.yaml.
Dùng lệnh này để xác nhận rằng các pod Ingress Controller đã được khởi động:
kubectl get pods -n ingress-nginx \
-l app.kubernetes.io/name=ingress-nginx --watch
NAME READY STATUS RESTARTS AGE
ingress-nginx-admission-create-l2jhk 0/1 Completed 0 13m
ingress-nginx-admission-patch-hsrzf 0/1 Completed 0 13m
ingress-nginx-controller-c96557986-m47rq 1/1 Running 0 13m
Nhấn CTRL+C để trở về dấu nhắc lệnh.
Bây giờ, chúng ta sẽ kiểm xem load balancer của DigitalOcean đã được tạo thành công hay chưa bằng cách lấy thông tin chi tiết của service với kubectl:
kubectl get svc --namespace=ingress-nginx
Sau vài phút, bạn sẽ thấy một địa chỉ IP bên ngoài (external IP), tương ứng với địa chỉ IP của load balancer:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller LoadBalancer 10.245.201.120 203.0.113.0 80:31818/TCP,443:31146/TCP 14m
ingress-nginx-controller-admission ClusterIP 10.245.239.119 <none> 443/TCP 14m
Ghi lại địa chỉ IP này vì bạn sẽ cần nó ở bước sau.
Lưu ý: Mặc định, service LoadBalancer của Nginx Ingress có service.spec.externalTrafficPolicy được set là Local. Giá trị này dẫn toàn bộ lưu lượng truy cập của load balancer đến các node đang chạy pod Nginx Ingress. Các node khác sẽ cố tình fail kiểm tra tình trạng (health check) của load balancer để lưu lượng Ingress không được dẫn đến chúng. Chính sách lưu lượng truy cập bên ngoài nằm ngoài phạm vi của bài này, nhưng để tìm hiểu thêm, bạn có thể tham khảo bài này và từ tài liệu Kubernetes chính thức.
Load balancer này nhận lưu lượng truy cập trên các cổng HTTP 80 và HTTPS 443, và chuyển tiếp nó đến pod Ingress Controller. Sau đó, Ingress Controller sẽ định tuyến lưu lượng truy cập đến service backend phù hợp.
Bây giờ chúng ta có thể trỏ các bản ghi DNS của mình vào load balancer bên ngoài này và tạo một số Ingress Resource để triển khai các rule định tuyến lưu lượng truy cập.
Bước 3: Tạo Ingress Resource
Hãy bắt đầu bằng cách tạo một Ingress Resource đơn giản để định tuyến lưu lượng đến một subdomain nhất định tới một service backend tương ứng.
Trong hướng dẫn này, chúng ta sẽ sử dụng tên miền thử nghiệm example.com. Bạn nên thay thế bằng tên miền mà bạn sở hữu.
Trước tiên, chúng ta sẽ tạo một rule đơn giản để định tuyến lưu lượng truy cập cho echo1.example.com tới service backend echo1 và lưu lượng cho echo2.example.com tới service echo2.
Đầu tiên mở file echo_ingress.yaml:
nano echo_ingress.yaml
Rồi paste vào định nghĩa ingress sau đây:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: echo-ingress
spec:
rules:
- host: echo1.example.com
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: echo1
port:
number: 80
- host: echo2.example.com
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: echo2
port:
number: 80
Lưu file này lại sau khi bạn đã chỉnh sửa xong các rule Ingress.
Nội dung trên chỉ định rằng ta muốn tạo một Ingress Resource có tên echo-ingress và dẫn lưu lượng dựa trên header Host. Header Host của một request HTTP chỉ định tên miền của server đích. Bạn có thể xem thêm ở Mozilla Developer Network để tìm hiểu thêm về header này.
Các request có host là echo1.example.com sẽ được chuyển hướng đến backend echo1 đã được thiết lập ở bước 1, và các request có host là echo2.example.com sẽ được chuyển hướng đến backend echo2.
Bây giờ bạn có thể tạo Ingress bằng kubectl:
kubectl apply -f echo_ingress.yaml
Bạn sẽ thấy output xác nhận việc tạo Ingress:
ingress.networking.k8s.io/echo-ingress created
Để kiểm tra Ingress, hãy vào nơi quản lý DNS của bạn và tạo các bản ghi A cho echo1.example.com và echo2.example.com để trỏ đến external IP của DigitalOcean Load Balancer. Địa chỉ này là địa chỉ IP bên ngoài của service ingress-nginx mà chúng ta đã lấy ở bước trước.
Nếu bạn đang sử dụng DigitalOcean để quản lý các bản ghi DNS của tên miền, hãy làm theo bài hướng dẫn này.
Sau khi bạn đã tạo các bản ghi DNS cần thiết cho echo1.example.com và echo2.example.com, bạn có thể kiểm tra Ingress Controller và Resource đã tạo với lệnh curl.
Chạy lệnh sau từ máy local của bạn:
curl echo1.example.com
Bạn sẽ nhận được response sau từ service echo1:
echo1
Điều này xác nhận rằng request của bạn đến echo1.example.com đang được dẫn chính xác thông qua Nginx ingress đến service backend echo1.
Thực hiện kiểm tra tương tự cho echo2:
curl echo2.example.com
Output cho lệnh trên phải nên là:
echo2
Nó xác nhận rằng request của bạn đến echo2.example.com đang được định tuyến chính xác thông qua Nginx ingress đến Service backend echo2.
Đến đây, bạn đã thiết lập thành công một Nginx Ingress đơn giản để thực hiện định tuyến dựa trên virtual host. Trong bước tiếp theo, chúng ta sẽ cài đặt cert-manager để cung cấp chứng chỉ TLS cho Ingress và bật giao thức HTTPS.
Bước 4: Cài đặt và Cấu hình Cert-Manager
Trong bước này, chúng ta sẽ cài đặt phiên bản v1.7.1 của cert-manager vào cluster. Đây là một add-on của Kubernetes để cung cấp chứng chỉ TLS từ Let’s Encrypt và các tổ chức phát hành chứng chỉ (CA) khác. Nó cũng đồng thời quản lý vòng đời của các chứng chỉ này.
Chứng chỉ được yêu cầu và cấu hình tự động bằng cách sử dụng annotation cho Ingress Resource, thêm một mục tls vào spec của Ingress, và cấu hình một hoặc nhiều Issuer hoặc ClusterIssuer để chỉ định tổ chức CA bạn muốn dùng. Để tìm hiểu thêm về các đối tượng Issuer và ClusterIssuer, hãy tham khảo tài liệu cert-manager chính thức về Issuers.
Làm theo hướng dẫn này để cài đặt cert-manager và các Custom Resource Definition (CRD) của nó như Issuer và ClusterIssuer. Lưu ý rằng một namespace tên là cert-manager sẽ được tạo để chưa các đối tượng cert-manager:
kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.7.1/cert-manager.yaml
Bạn sẽ thấy output như sau:
customresourcedefinition.apiextensions.k8s.io/certificaterequests.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/certificates.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/challenges.acme.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/clusterissuers.cert-manager.io created
. . .
deployment.apps/cert-manager-webhook created
mutatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook created
validatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook created
Kiểm tra thiết lập của chúng ta bằng cách xem Namespace cert-manager các pod đang chạy:
kubectl get pods --namespace cert-manager
NAME READY STATUS RESTARTS AGE
cert-manager-578cd6d964-hr5v2 1/1 Running 0 99s
cert-manager-cainjector-5ffff9dd7c-f46gf 1/1 Running 0 100s
cert-manager-webhook-556b9d7dfd-wd5l6 1/1 Running 0 99s
Kết quả trên cho thấy ta đã cài đặt cert-manager thành công.
Trước khi chúng ta bắt đầu phát hành chứng chỉ cho các tên miền echo1.example.com và echo2.example.com, chúng ta cần tạo một Issuer, chỉ định tổ chức phát hành chứng chỉ (nơi có thể lấy chứng chỉ x509 đã ký).
Trong bài này, chúng ta sẽ sử dụng Let’s Encrypt, tổ chức cung cấp chứng chỉ TLS miễn phí. Họ có server staging để kiểm tra cấu hình chứng chỉ lẫn server production để triển khai chứng chỉ TLS có thể xác minh được.
Hãy tạo một ClusterIssuer thử nghiệm để đảm bảo cơ chế cung cấp chứng chỉ hoạt động chính xác. Một ClusterIssuer không bị giới hạn trong namespace và có thể được sử dụng bởi các resource Certificate trong bất kỳ namespace nào.
Mở file staging_issuer.yaml:
nano staging_issuer.yaml
Và paste manifest ClusterIssuer sau đây:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
namespace: cert-manager
spec:
acme:
# The ACME server URL
server: https://acme-staging-v02.api.letsencrypt.org/directory
# Email address used for ACME registration
email: your_email_address_here
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-staging
# Enable the HTTP-01 challenge provider
solvers:
- http01:
ingress:
class: nginx
Nội dung trên chỉ định rằng ta muốn tạo một ClusterIssuer tên là letsencrypt-staging và sử dụng server staging của Let’s Encrypt. Sau này chúng ta sẽ sử dụng server production để triển khai chứng chỉ. Nhưng vì server production có giới hạn số lượng request, bạn nên sử dụng URL staging cho mục đích kiểm tra này.
Tiếp theo, chúng ta chỉ định một địa chỉ email để đăng ký chứng chỉ và tạo một Kubernetes Secret tên là letsencrypt-staging để lưu trữ khóa riêng (private key) của tài khoản ACME. Chúng ta cũng sử dụng cơ chế challenge HTTP-01. Để tìm hiểu thêm về các tham số này, hãy tham khảo tài liệu chính thức về Issuers.
Triển khai ClusterIssuer bằng kubectl:
kubectl create -f staging_issuer.yaml
Bạn sẽ thấy output sau:
clusterissuer.cert-manager.io/letsencrypt-staging created
Bây giờ chúng ta sẽ lặp lại quy trình này để tạo ClusterIssuer cho production. Lưu ý rằng chứng chỉ sẽ chỉ được tạo sau khi sử dụng annotation và cập nhật Ingress resource được cung cấp ở bước trước.
Mở file prod_issuer.yaml:
nano prod_issuer.yaml
Và paste manifest ClusterIssuer sau đây:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
namespace: cert-manager
spec:
acme:
# The ACME server URL
server: https://acme-v02.api.letsencrypt.org/directory
# Email address used for ACME registration
email: your_email_address_here
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-prod
# Enable the HTTP-01 challenge provider
solvers:
- http01:
ingress:
class: nginx
Lưu ý URL server ACME và tên khóa secret letsencrypt-prod có khác ở bước trước.
Khi bạn đã chỉnh sửa xong, hãy lưu và đóng file.
Triển khai Issuer này bằng kubectl:
kubectl create -f prod_issuer.yaml
Bạn sẽ thấy output sau:
clusterissuer.cert-manager.io/letsencrypt-prod created
Sau khi đã tạo các ClusterIssuer staging và prod của Let’s Encrypt, chúng tacó thể sửa Ingress Resource đã tạo ở trên và bật mã hóa TLS cho các đường dẫn của echo1.example.com và echo2.example.com.
Nếu bạn đang sử dụng DigitalOcean Kubernetes, trước tiên bạn cần thực hiện một giải pháp tạm thời để các pod có thể giao tiếp với nhau thông qua Ingress. Còn không, hãy bỏ qua việc này và chuyển đến Bước 6.
Bước 5: Kích hoạt giao tiếp pod qua load balancer (không bắt buộc)
Trước khi cung cấp chứng chỉ từ Let’s Encrypt, cert-manager trước tiên tiến hành tự kiểm tra để đảm bảo rằng Let’s Encrypt có thể tiếp cận pod cert-manager dùng để xác thực tên miền của bạn. Để kiểm tra này thành công trên DigitalOcean Kubernetes, bạn cần bật giao tiếp Pod-Pod thông qua load balancer Nginx Ingress.
Để làm điều này, chúng ta sẽ tạo một bản ghi DNS A trỏ đến external IP của load balancer, và thêm annotation vào manifest Service Nginx Ingress với subdomain này.
Bắt đầu bằng cách truy cập trang quản lý DNS của bạn và tạo một bản ghi A cho workaround.example.com trỏ đến external IP của DigitalOcean Load Balancer. Đây là địa chỉ IP cho Service ingress-nginx mà chúng ta đã lấy ở Bước 2.
Nếu bạn đang sử dụng DigitalOcean để quản lý DNS cho tên miền, tham khảo bài này để biết cách tạo bản ghi A. Ở đây chúng ta sử dụng subdomain workaround nhưng bạn có thể tự do sử dụng bất kỳ subdomain nào bạn muốn.
Sau khi bạn đã tạo bản ghi DNS trỏ đến load balancer Ingress, hãy thêm annotation do-loadbalancer-hostname vào Service LoadBalancer của Ingress. Mở một file có tên ingress_nginx_svc.yaml và paste vào manifest LoadBalancer sau:
Và paste manifest ClusterIssuer sau đây:
apiVersion: v1
kind: Service
metadata:
annotations:
service.beta.kubernetes.io/do-loadbalancer-enable-proxy-protocol: 'true'
service.beta.kubernetes.io/do-loadbalancer-hostname: "workaround.example.com"
labels:
helm.sh/chart: ingress-nginx-4.0.6
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/version: 1.1.1
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/component: controller
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
type: LoadBalancer
externalTrafficPolicy: Local
ports:
- name: http
port: 80
protocol: TCP
targetPort: http
- name: https
port: 443
protocol: TCP
targetPort: https
selector:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/component: controller
Manifest này được lấy từ file manifest Nginx Ingress hoàn chỉnh mà bạn đã tạo ở Bước 2. Nhớ là bạn phải sao chép manifest Service tương ứng với phiên bản Nginx Ingress bạn đã cài đặt (là 1.1.1 trong bài này). Cũng hãy nhớ đặt annotation do-loadbalancer-hostname thành tên miền workaround.example.com.
Đóng file sau khi chỉnh sửa xong. Sau đó thay đổi service ingress-nginx-controller đang chạy bằng kubectl apply:
kubectl apply -f ingress_nginx_svc.yaml
Bạn sẽ thấy output như sau:
service/ingress-nginx-controller configured
Output này xác nhận rằng bạn đã thêm annotation cho service ingress-nginx-controller và các pod trong cluster của bạn giờ đây có thể giao tiếp với nhau bằng cách sử dụng load balancer này.
Bước 6: Phát hành chứng chỉ Staging và Production từ Let’s Encrypt
Để phát hành chứng chỉ TLS staging cho tên miền, chúng ta sẽ thêm annotation vào echo_ingress.yaml với ClusterIssuer đã tạo ở Bước 4. Nó sẽ sử dụng ingress-shim để tự động tạo và phát hành chứng chỉ cho các tên miền được chỉ định trong manifest Ingress.
Mở echo_ingress.yaml:
nano echo_ingress.yaml
Thêm nội dung sau vào manifest Ingress resource:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: echo-ingress
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-staging"
kubernetes.io/ingress.class: "nginx"
spec:
tls:
- hosts:
- echo1.example.com
- echo2.example.com
secretName: echo-tls
rules:
- host: echo1.example.com
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: echo1
port:
number: 80
- host: echo2.example.com
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: echo2
port:
number: 80
Ở đây chúng ta thêm một annotation để đặt cert-manager ClusterIssuer thành letsencrypt-staging (là ClusterIssuer chứng chỉ thử nghiệm đã tạo ở Bước 4). Ngoài ra cũng có một annotation mô tả loại ingress (trong trường hợp này là nginx).
Khối tls được dùng để chỉ định các host mà chúng ta muốn lấy chứng chỉ và chỉ định một secretName. Secret này sẽ chứa khóa riêng TLS và chứng chỉ đã được phát hành. Nhớ thay thế example.com bằng tên miền mà bạn đã tạo bản ghi DNS.
Lưu và đóng file sau khi đã thực hiện xong các thay đổi.
Bây giờ chúng ta sẽ đẩy bản cập nhật này lên đối tượng Ingress hiện có bằng kubectl apply:
kubectl apply -f echo_ingress.yaml
Ta sẽ có output như sau:
ingress.networking.k8s.io/echo-ingress configured
Bạn có thể sử dụng kubectl describe để theo dõi trạng thái của các thay đổi Ingress bạn vừa áp dụng:
kubectl describe ingress
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal UPDATE 6s (x3 over 80m) nginx-ingress-controller Ingress default/echo-ingress
Normal CreateCertificate 6s cert-manager Successfully created Certificate "echo-tls"
Khi chứng chỉ đã được tạo thành công, bạn có thể chạy lệnh describe với nó để xác nhận:
kubectl describe certificate
Bạn sẽ thấy output sau trong mục Events:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Requested 64s cert-manager Created new CertificateRequest resource "echo-tls-vscfw"
Normal Issuing 40s cert-manager The certificate has been successfully issued
Kết quả này xác nhận rằng chứng chỉ TLS đã được phát hành thành công và mã hóa HTTPS hiện đã hoạt động cho hai tên miền đã cấu hình.
Bây giờ chúng ta đã có thể gửi một request đến server echo backend để kiểm tra xem HTTPS có hoạt động đúng hay không. Chạy lệnh wget sau để gửi một request đến echo1.example.com và in các header trong response ra STDOUT:
wget --save-headers -O- echo1.example.com
Bạn sẽ thấy output sau:
. . .
HTTP request sent, awaiting response... 308 Permanent Redirect
. . .
ERROR: cannot verify echo1.example.com's certificate, issued by ‘ERROR: cannot verify echo1.example.com's certificate, issued by ‘CN=(STAGING) Artificial Apricot R3,O=(STAGING) Let's Encrypt,C=US’:
Unable to locally verify the issuer's authority.
To connect to echo1.example.com insecurely, use `--no-check-certificate'.
Theo như trên thì HTTPS đã được bật thành công nhưng chứng chỉ không xác minh được (vì đây là chứng chỉ giả tạm thời do server staging của Let’s Encrypt phát hành).
Sau khi chúng ta đã kiểm tra mọi thứ hoạt động bằng chứng chỉ tạm thời này, chúng ta có thể triển khai chứng chỉ production cho hai host echo1.example.com và echo2.example.com. Để làm điều này, chúng ta sẽ sử dụng ClusterIssuer letsencrypt-prod.
Cập nhật echo_ingress.yaml để sử dụng letsencrypt-prod:
nano echo_ingress.yaml
Thực hiện các thay đổi sau trong file:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: echo-ingress
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
kubernetes.io/ingress.class: "nginx"
spec:
tls:
- hosts:
- echo1.example.com
- echo2.example.com
secretName: echo-tls
rules:
- host: echo1.example.com
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: echo1
port:
number: 80
- host: echo2.example.com
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: echo2
port:
number: 80
Ở đây, chúng ta sửa tên ClusterIssuer thành letsencrypt-prod. Nhớ lưu và đóng file khi xong và triển khai các thay đổi bằng kubectl apply:
kubectl apply -f echo_ingress.yaml
ingress.networking.k8s.io/echo-ingress configured
Đợi vài phút để server production của Let’s Encrypt phát hành chứng chỉ. Bạn có thể theo dõi tiến trình của nó bằng cách sử dụng kubectl describe trên đối tượng certificate:
kubectl describe certificate echo-tls
Bạn thấy output sau nghĩa là chứng chỉ đã được phát hành thành công:
Normal Issuing 28s cert-manager Issuing certificate as Secret was previously issued by ClusterIssuer.cert-manager.io/letsencrypt-staging
Normal Reused 28s cert-manager Reusing private key stored in existing Secret resource "echo-tls"
Normal Requested 28s cert-manager Created new CertificateRequest resource "echo-tls-49gmn"
Normal Issuing 2s (x2 over 4m52s) cert-manager The certificate has been successfully issued
Bây giờ chúng ta sẽ thực hiện kiểm tra bằng curl để xác minh rằng HTTPS đang hoạt động đúng:
curl echo1.example.com
Bạn sẽ thấy kết quả sau:
<html>
<head><title>308 Permanent Redirect</title></head>
<body>
<center><h1>308 Permanent Redirect</h1></center>
<hr><center>nginx/1.15.9</center>
</body>
</html>
Điều này cho thấy các request HTTP đang được chuyển hướng để sử dụng HTTPS.
Chạy curl đến https://echo1.example.com:
curl https://echo1.example.com
Bây giờ bạn sẽ thấy output sau:
echo1
Bạn có thể chạy lệnh trước đó với cờ verbose -v để tìm hiểu sâu hơn về quá trình handshake chứng chỉ và xác minh thông tin chứng chỉ.
Đến đây, ta đã cấu hình thành công HTTPS bằng chứng chỉ Let’s Encrypt cho Nginx Ingress của mình.
Kết luận
Trong hướng dẫn này, bạn đã thiết lập một Nginx Ingress để cân bằng tải và định tuyến các request bên ngoài đến các service backend bên trong cluster Kubernetes. Bạn cũng đã bảo mật Ingress bằng cách cài đặt trình cung cấp chứng chỉ cert-manager và thiết lập chứng chỉ Let’s Encrypt cho hai đường dẫn host.
Có nhiều giải pháp thay thế khác cho Nginx Ingress Controller mà bạn có thể cân nhắc. Để tìm hiểu thêm, hãy tham khảo mục Ingress controllers từ tài liệu Kubernetes chính thức.