Reading Time: 11 minutes

Kubernetes Ingresses cung cấp một phương thức linh hoạt để định tuyến lưu lượng từ bên ngoài cluster đến các Service nội bộ. Tài nguyên Ingress là các đối tượng trong Kubernetes dùng để định nghĩa các rule cho việc định tuyến lưu lượng HTTP và HTTPS tới các Service đó.

Cài đặt Nginx Ingress cho Kubernetes

Để các rule này hoạt động được, ta cần phải có một bộ điều khiển (controller) Ingress để triển khai chúng bằng cách tiếp nhận lưu lượng (thường thông qua một Load Balancer) và chuyển đến các Service phù hợp. Hầu hết Ingress Controller chỉ sử dụng một Load Balancer toàn cục duy nhất cho tất cả các Ingress. Lựa chọn này hiệu quả hơn việc tạo Load Balancer cho mỗi Service mà chúng ta muốn expose (công khai).

Helm là một trình quản lý package dùng cho Kubernetes. Sử dụng Helm Charts với Kubernetes sẽ mang lại khả năng tùy chỉnh cấu hình và quản lý lifecycle (vòng đời), cho phép cập nhật, rollback và xóa ứng dụng Kubernetes.

Trong bài hướng dẫn này, chúng ta sẽ cài đặt bản Ingress Controller (do chính phía Kubernetes phát triển) dùng Nginx bằng Helm. Tiếp theo, ta sẽ tạo một Ingress Resource để định tuyến lưu lượng từ domain của bạn đến các các service ví dụ phía back-end. Chúng ta cũng sẽ cài đặt Cert-Manager vào cluster để tự động cấp chứng chỉ TLS từ Let’s Encrypt, giúp bảo mật các Ingress.

Những thứ cần chuẩn bị

  • Cài đặt một Kubernetes cluster phiên bản 1.20 trở lên và thiết lập cấu hình kết nối của bạn làm mặc định cho kubectl. Bài này sẽ sử dụng một Kubernetes cluster trên DigitalOcean với 3 node, nhưng bạn cũng có thể tự tạo cluster cho riêng mình ở bất kì đâu. Hãy tham khảo tài liệu chính thức từ DigitalOcean nếu bạn muốn tạo Kubernetes trên nền tảng này.
  • Cài đặt công cụ dòng lệnh kubectl trên môi trường local và cấu hình nó để kết nối tới cluster của bạn. Bạn có thể đọc thêm về cách cài đặt kubectl trong tài liệu chính thức của nó. Nếu bạn sử dụng DigitalOcean Kubernetes cluster, hướng dẫn cấu hình kubectl có trong mục Connect to your Cluster (hiển thị sau khi tạo cluster), hoặc bạn có thể tham khảo bài How to Connect to a DigitalOcean Kubernetes Cluster.
  • Cài đặt công cụ chính thức của DigitalOcean, doctl, trên máy của bạn. Xem thêm tài liệu chính thức của nó để học cách sử dụng công cụ này.
  • Cài đặt trình quản lý package Helm 3 trong môi trường dev của bạn. Hoàn thành bước 1 của bài hướng dẫn hướng dẫn cài đặt Kubernetes Clusters với Helm 3.
  • Đăng ký một tên miền với hai record A đã được cấu hình sẵn. Bài hướng dẫn này sẽ sử dụng first-example.comsecond-example.com. Bạn có thể mua tên miền từ Namecheap, nhận miễn phí từ Freenom, hoặc sử dụng bất kỳ nhà đăng ký tên miền nào khác. Các record A này sẽ được trỏ tới một Load Balancer mà chúng ta sẽ tạo ở Bước 2.

Cài đặt Nginx Ingress cho Kubernetes

Bước 1: Triển khai ứng dụng Hello World

Trước khi deploy Nginx Ingress, chúng ta sẽ deploy một ứng dụng “Hello World” tên là hello-kubernetes để có sẵn các Service làm đích cho việc định tuyến lưu lượng. Để xác nhận Nginx Ingress hoạt động chính xác ở các bước sau, chúng ta sẽ deploy ứng dụng này hai lần. Mỗi lần sẽ có một thông điệp chào mừng khác nhau (hiển thị khi bạn truy cập từ trình duyệt).

Chúng ta sẽ lưu cấu hình deployment trên máy local. Nếu muốn, bạn có thể tạo một thư mục riêng cho bài hướng dẫn này để lưu các file cấu hình.

Cấu hình deployment đầu tiên sẽ được lưu trong file tên là hello-kubernetes-first.yaml. Hãy tạo file này bằng editor bạn hay dùng như nano:

nano hello-kubernetes-first.yaml

Thêm nội dung sau vào file:

apiVersion: v1
kind: Service
metadata:
  name: hello-kubernetes-first
spec:
  type: ClusterIP
  ports:
  - port: 80
    targetPort: 8080
  selector:
    app: hello-kubernetes-first
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-kubernetes-first
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hello-kubernetes-first
  template:
    metadata:
      labels:
        app: hello-kubernetes-first
    spec:
      containers:
      - name: hello-kubernetes
        image: paulbouwer/hello-kubernetes:1.10
        ports:
        - containerPort: 8080
        env:
        - name: MESSAGE
          value: Hello from the first deployment!

Cấu hình này định nghĩa một Deployment và một Service. Deployment bao gồm ba replica (bản sao) của image paulbouwer/hello-kubernetes:1.7 và một biến môi trường tên là MESSAGE (bạn sẽ thấy giá trị này khi truy cập ứng dụng). Service ở đây được định nghĩa để expose Deployment bên trong cluster tại port 8080. Lưu và đóng file.

Sau đó, tạo phiên bản đầu tiên này của ứng dụng hello-kubernetes trong Kubernetes bằng cách chạy lệnh sau:

kubectl create -f hello-kubernetes-first.yaml

Tùy chọn -f chỉ định lệnh kubectl sử dụng file hello-kubernetes-first.yaml.

Bạn sẽ nhận được output như sau:

service/hello-kubernetes-first created
deployment.apps/hello-kubernetes-first created

Để kiểm tra Service đã được tạo thành công chưa, chạy lệnh sau:

kubectl get service hello-kubernetes-first

Output sẽ có dạng như sau:

NAME                     TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
hello-kubernetes-first   ClusterIP   10.245.124.46   <none>        80/TCP    7s

Bạn sẽ thấy Service vừa tạo có một CLUSTER-IP được gán cho nó, đồng nghĩa Service đang hoạt động bình thường. Toàn bộ lưu lượng gửi đến Service này sẽ được chuyển tiếp tới Deployment tương ứng trên port 8080.

Sau khi đã deploy phiên bản đầu tiên của ứng dụng hello-kubernetes, chúng ta sẽ tiếp tục với phiên bản thứ hai. Tạo một file mới tên là hello-kubernetes-second.yaml:

nano hello-kubernetes-second.yaml

Thêm nội dung sau vào file:

apiVersion: v1
kind: Service
metadata:
  name: hello-kubernetes-second
spec:
  type: ClusterIP
  ports:
  - port: 80
    targetPort: 8080
  selector:
    app: hello-kubernetes-second
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-kubernetes-second
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hello-kubernetes-second
  template:
    metadata:
      labels:
        app: hello-kubernetes-second
    spec:
      containers:
      - name: hello-kubernetes
        image: paulbouwer/hello-kubernetes:1.10
        ports:
        - containerPort: 8080
        env:
        - name: MESSAGE
          value: Hello from the second deployment!

Phiên bản này có cấu trúc tương tự như cấu hình trước đó. Để tránh xung đột, chúng ta thay đổi giá trị name dùng cho Deployment và Service. Chúng ta cũng sẽ cập nhật biến MESSAGE của ứng dụng hello-kubernetes (sẽ hiển thị trên trình duyệt). Nhớ lưu và đóng file.

Bây giờ, hãy tạo các resource này trong Kubernetes bằng lệnh sau:

kubectl create -f hello-kubernetes-second.yaml

Output của nó sẽ là:

service/hello-kubernetes-second created
deployment.apps/hello-kubernetes-second created

Kiểm tra xem Service thứ hai đã hoạt động chưa bằng cách liệt kê tất cả các Service hiện có:

kubectl get service

Output sẽ trông giống như sau:

NAME                      TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
hello-kubernetes-first    ClusterIP   10.245.124.46    <none>        80/TCP    49s
hello-kubernetes-second   ClusterIP   10.245.254.124   <none>        80/TCP    10s
kubernetes                ClusterIP   10.245.0.1       <none>        443/TCP   65m

Cả hello-kubernetes-firsthello-kubernetes-second đều được liệt kê, cho thấy Kubernetes đã tạo chúng thành công.

Chúng ta đã tạo hai deployment của ứng dụng hello-kubernetes cùng với các Service tương ứng. Mỗi deployment có một thông điệp khác nhau được thiết lập trong cấu hình để phân biệt chúng trong bước kiểm tra. Ở bước tiếp theo, chúng ta sẽ cài đặt Ingress Controller với Nginx.

Bước 2: Cài đặt Ingress Controller sử dụng Nginx từ Kubernetes

Bây giờ, chúng ta sẽ cài đặt Nginx Ingress Controller do Kubernetes phát triển bằng Helm.

Nginx Ingress Controller bao gồm một Pod và một Service. Pod này chạy Controller, liên tục truy vấn endpoint /api trên API server của cluster để cập nhật thông tin về các Ingress Resource khả dụng. Service đó có type là LoadBalancer.

Vì chúng ta đang deploy lên DigitalOcean, cluster sẽ tự động tạo một Load Balancer của chính DigitalOcean. Toàn bộ lưu lượng từ bên ngoài sẽ đi qua Load Balancer này để vào Controller. Sau đó, Controller sẽ định tuyến lưu lượng đến các Service phù hợp định nghĩa trong các Ingress Resource.

Chỉ Service LoadBalancer mới biết địa chỉ IP tạo tự động của Load Balancer. Một số ứng dụng (ví dụ: ExternalDNS) cũng cần biết địa chỉ IP này nhưng chỉ có thể đọc cấu hình từ Ingress. Controller có thể được cấu hình để đăng tải địa chỉ IP này trên mỗi Ingress bằng cách thiết lập tham số controller.publishService.enabled thành true trong quá trình cài đặt với helm install. Chúng ta nên bật thiết lập này để hỗ trợ các ứng dụng phụ thuộc vào địa chỉ IP của Load Balancer.

Để cài đặt Nginx Ingress Controller vào cluster, trước tiên chúng ta cần thêm repository của nó vào Helm bằng lệnh:

helm repo add ingress-nginx <https://kubernetes.github.io/ingress-nginx>

Output:

"ingress-nginx" has been added to your repositories

Tiếp theo, cập nhật các chart repository:

helm repo update

Quá trình này có thể mất một chút thời gian:

Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "ingress-nginx" chart repository
Update Complete. ⎈Happy Helming!⎈

Cuối cùng, chạy lệnh sau để cài đặt Nginx Ingress:

helm install nginx-ingress ingress-nginx/ingress-nginx --set controller.publishService.enabled=true

Lệnh này cài đặt Nginx Ingress Controller từ chart repository stable, đặt tên cho Helm release là ingress-nginx, và thiết lập tham số controller.publishService.enabled thành true.

Sau khi lệnh chạy xong, bạn sẽ nhận được output tương tự như bản rút gọn sau:

NAME: nginx-ingress
LAST DEPLOYED: Thu Dec  1 11:40:28 2022
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
...

Helm đã log lại các resource mà nó tạo ra trong Kubernetes trong quá trình cài đặt chart.

Chạy lệnh sau để theo dõi quá trình Load Balancer trở nên khả dụng:

kubectl --namespace default get services -o wide -w nginx-ingress-ingress-nginx-controller

Lệnh này lấy thông tin service Nginx Ingress trong namespace ingress-nginx và hiển thị thông tin của service đó. Nhưng lệnh sẽ không kết thúc ngay. Với tham số -w, chương trình sẽ theo dõi và cập nhật output khi có thay đổi.

Trong khi chờ Load Balancer sẵn sàng, bạn có thể thấy trạng thái <pending>:

NAME                                     TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)                      AGE   SELECTOR
nginx-ingress-ingress-nginx-controller   LoadBalancer   10.245.3.122   <pending>     80:30953/TCP,443:30869/TCP   36s   ...

Sau một khoảng thời gian, địa chỉ IP của Load Balancer vừa tạo sẽ xuất hiện trong cột EXTERNAL-IP:

NAME                                     TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)                      AGE   SELECTOR
nginx-ingress-ingress-nginx-controller   LoadBalancer   10.245.3.122   167.99.16.184   80:30953/TCP,443:30869/TCP   2m29s   ...

Tiếp theo, bạn cần đảm bảo hai domain của mình trỏ đến địa chỉ IP của Load Balancer này thông qua các record A. Việc này được thực hiện tại trang quản lý DNS của nhà cung cấp tên miền. Để cấu hình record DNS trên DigitalOcean, hãy tham khảo hướng dẫn chính thức của họ.

Chúng ta đã cài đặt Nginx Ingress Controller để định tuyến lưu lượng HTTP và HTTPS từ Load Balancer đến các back-end Service phù hợp (định nghĩa trong các Ingress Resource). Ở bước tiếp theo, chúng ta sẽ expose các deployment của ứng dụng hello-kubernetes bằng một Ingress Resource.

Bước 3: Expose ứng dụng bằng Ingress

Bây giờ, chúng ta sẽ tạo một Ingress Resource và dùng nó để expose các deployment của ứng dụng hello-kubernetes tại các domain đã chuẩn bị. Sau đó, chúng ta sẽ kiểm tra bằng cách truy cập các domain này từ trình duyệt.

Chúng ta sẽ lưu cấu hình Ingress vào file hello-kubernetes-ingress.yaml. Tạo file này bằng editor bạn hay dùng:

nano hello-kubernetes-ingress.yaml

Thêm nội dung sau vào file đó:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: hello-kubernetes-ingress
  annotations:
    kubernetes.io/ingress.class: nginx
spec:
  rules:
  - host: "hw1.your_domain_name"
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: hello-kubernetes-first
            port:
              number: 80
  - host: "hw2.your_domain_name"
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: hello-kubernetes-second
            port:
              number: 80

Chúng ta đã định nghĩa một Ingress Resource tên là hello-kubernetes-ingress. Tiếp theo, chúng ta chỉ định hai rule cho host: first-example.com sẽ được định tuyến tới Service hello-kubernetes-first, và second-example.com sẽ được định tuyến tới Service của deployment thứ hai (hello-kubernetes-second).

Hãy nhớ thay thế các domain được highlight bằng domain thật của bạn, rồi lưu và đóng file.

Tạo Ingress Resource này trong Kubernetes bằng cách chạy lệnh sau:

kubectl apply -f hello-kubernetes-ingress.yaml

Bây giờ, bạn có thể truy cập first-example.com trên trình duyệt. Trang web từ deployment đầu tiên sẽ hiển thị như sau:

Màn hình deployment thứ nhất khi cài đặt Nginx Ingress cho Kubernetes

Tương tự, trang second-example.com (từ deployment thứ hai) sẽ hiển thị một thông điệp khác:

Màn hình deployment thứ hai

Như vậy, ta đã kiểm tra và xác nhận Ingress Controller đã định tuyến chính xác các request (cụ thể là từ hai domain của bạn đến hai Service khác nhau).

Chúng ta đã tạo và cấu hình một Ingress Resource để phục vụ các deployment của ứng dụng hello-kubernetes tại các domain của mình. Ở bước tiếp theo, chúng ta sẽ cài đặt Cert-Manager để bảo mật các Ingress Resource bằng chứng chỉ TLS miễn phí từ Let’s Encrypt.

Bước 4: Bảo mật Ingress bằng Cert-Manager

Để bảo mật các Ingress Resource, chúng ta sẽ cài đặt Cert-Manager, tạo một ClusterIssuer cho môi trường production, và chỉnh sửa cấu hình Ingress để sử dụng chứng chỉ TLS. Sau khi cài đặt và cấu hình xong, ứng dụng của bạn sẽ hỗ trợ HTTPS.

ClusterIssuer là các resource của Cert-Manager trong Kubernetes. Nó có chức năng cung cấp chứng chỉ TLS cho toàn bộ cluster. Nó là một loại Issuer cụ thể.

Trước khi cài đặt Cert-Manager vào cluster qua Helm, chúng ta sẽ tạo một namespace riêng cho nó:

kubectl create namespace cert-manager

Chúng ta cần thêm repository tên Jetstack Helm (nơi chứa chart Cert-Manager) vào Helm. Để làm điều đó, hãy chạy lệnh sau:

helm repo add jetstack <https://charts.jetstack.io>

Helm sẽ trả về output như sau:

"jetstack" has been added to your repositories

Sau đó, nhớ cập nhật cache chart của Helm:

helm repo update

Quá trình này có thể mất một chút thời gian:

Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "ingress-nginx" chart repository
...Successfully got an update from the "jetstack" chart repository
Update Complete. ⎈Happy Helming!⎈

Cuối cùng, cài đặt Cert-Manager vào namespace cert-manager bằng lệnh sau:

helm install cert-manager jetstack/cert-manager --namespace cert-manager --version v1.10.1 --set installCRDs=true

Trong lệnh này, chúng ta cũng thiết lập tham số installCRDs thành true để cài đặt các manifest CustomResourceDefinition (CRD) của Cert-Manager trong quá trình Helm install. Bạn có thể tham khảo ArtifactHub để tìm phiên bản mới nhất.

Bạn sẽ nhận được output như sau:

NAME: cert-manager
LAST DEPLOYED: Wed Nov 30 19:46:39 2022
NAMESPACE: cert-manager
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
cert-manager v1.10.1 has been deployed successfully!
...

Output này cho thấy việc cài đặt đã thành công.

Phần NOTES trong output (đã được rút gọn ở trên) cho biết chúng ta cần thiết lập một Issuer hoặc ClusterIssuer để cấp phát chứng chỉ TLS.

Bây giờ, chúng ta sẽ tạo một ClusterIssuer để cấp chứng chỉ từ Let’s Encrypt, và lưu cấu hình vào file production_issuer.yaml. Hãy tạo và mở file này:

nano production_issuer.yaml

Thêm nội dung sau vào file:

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    # Email address used for ACME registration
    email: your_email_address
    server: <https://acme-v02.api.letsencrypt.org/directory>
    privateKeySecretRef:
      # Name of a secret used to store the ACME account private key
      name: letsencrypt-prod-private-key
    # Add a single challenge solver, HTTP01 using nginx
    solvers:
    - http01:
        ingress:
          class: nginx

Cấu hình này chỉ định một ClusterIssuer sẽ liên hệ với Let’s Encrypt để lấy chứng chỉ. Bạn cần thay thế YOUR_EMAIL_ADDRESS bằng địa chỉ email của mình để nhận các thông báo về bảo mật và thời hạn của chứng chỉ.

Lưu và đóng file, rồi ap dụng cấu hình này bằng kubectl apply:

kubectl apply -f production_issuer.yaml

Bạn sẽ nhận được output như sau:

clusterissuer.cert-manager.io/letsencrypt-prod created

Sau khi Cert-Manager đã được cài đặt, chúng ta đã có thể tích hợp chứng chỉ TLS vào Ingress Resource đã định nghĩa ở bước trước. Mở file hello-kubernetes-ingress.yaml để chỉnh sửa:

nano hello-kubernetes-ingress.yaml

Thêm các dòng được highlight sau:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: hello-kubernetes-ingress
annotations:
  kubernetes.io/ingress.class: nginx
  cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  tls:
  - hosts:
    - hw1.your_domain
    - hw2.your_domain
    secretName: hello-kubernetes-tls
  rules:
  - host: "hw1.your_domain_name"
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: hello-kubernetes-first
            port:
              number: 80
  - host: "hw2.your_domain_name"
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: hello-kubernetes-second
            port:
              number: 80

Khối tls trong spec định nghĩa Secret sẽ lưu trữ chứng chỉ cho các trang web của bạn (liệt kê trong hosts). Các chứng chỉ này do ClusterIssuer tên là letsencrypt-prod cấp. secretName phải có tên độc nhất cho mỗi Ingress Resource bạn tạo.

Hãy nhớ thay thế first-example.comsecond-example.com bằng domain thật của bạn. Sau khi chỉnh sửa xong, lưu và đóng file.

Áp dụng lại cấu hình này vào cluster bằng lệnh sau:

kubectl apply -f hello-kubernetes-ingress.yaml

Bạn sẽ nhận được output như sau:

ingress.networking.k8s.io/hello-kubernetes-ingress configured

Sẽ mất vài phút để các server của Let’s Encrypt cấp chứng chỉ cho domain của bạn. Trong thời gian này, bạn có thể theo dõi tiến trình bằng cách kiểm tra output của lệnh sau:

kubectl describe certificate hello-kubernetes-tls

Phần cuối của output sẽ tương tự như sau:

Events:
  Type    Reason     Age    From                                       Message
  ----    ------     ----   ----                                       -------
  Normal  Issuing    2m34s  cert-manager-certificates-trigger          Issuing certificate as Secret does not exist
  Normal  Generated  2m34s  cert-manager-certificates-key-manager      Stored new private key in temporary Secret resource "hello-kubernetes-tls-hxtql"
  Normal  Requested  2m34s  cert-manager-certificates-request-manager  Created new CertificateRequest resource "hello-kubernetes-tls-jnnwx"
  Normal  Issuing    2m7s   cert-manager-certificates-issuing          The certificate has been successfully issued

Khi output thông báo Certificate is valid, bạn có thể thoát bằng cách nhấn CTRL+C.

Truy cập một trong các domain trên trên trình duyệt. Bạn sẽ thấy biểu tượng ổ khóa xuất hiện bên cạnh URL, cho thấy kết nối của bạn đã được mã hóa.

Trong bước này, chúng ta đã cài đặt Cert-Manager bằng Helm và tạo một ClusterIssuer cho Let’s Encrypt. Tiếp theo, chúng ta đã cập nhật Ingress Resource để sử dụng ClusterIssuer này cho việc tạo chứng chỉ TLS. Cuối cùng, chúng ta đã xác nhận HTTPS hoạt động chính xác bằng cách truy cập một trong các domain trên trình duyệt.

Kết luận

Như vậy, bạn đã cài đặt thành công Nginx Ingress Controller và Cert-Manager trên Kubernetes cluster của DigitalOcean bằng Helm. Giờ đây, bạn đã có thể expose các ứng dụng của mình ra internet tại các domain tùy chọn, với kết nối được bảo mật bằng chứng chỉ TLS từ Let’s Encrypt.

0 Bình luận

Đăng nhập để thảo luận

Chuyên mục Hướng dẫn

Tổng hợp các bài viết hướng dẫn, nghiên cứu và phân tích chi tiết về kỹ thuật, các xu hướng công nghệ mới nhất dành cho lập trình viên.

Đăng ký nhận bản tin của chúng tôi

Hãy trở thành người nhận được các nội dung hữu ích của CyStack sớm nhất

Xem chính sách của chúng tôi Chính sách bảo mật.

Đăng ký nhận Newsletter

Nhận các nội dung hữu ích mới nhất