Published on

Cài đặt Metallb và Ingress Nginx trên Bare metal Kubernetes cluster

Giới thiệu

Trong các bài viết trước, mình đã giới thiệu về cách xây dựng một HomeLab để học về Kuberentes. Các bước cài đặt cơ bản đã xong, bước tiếp theo sẽ triển khai các ứng dụng trên Cluster đó. Nếu chưa xem các bài viết trước, bạn có thể xem lại để dễ theo dõi

  1. Cài đặt Kubernetes cluster trên Ubuntu server 22.04
  2. K8s cluster trên Ubuntu: Cài đặt Kubernetes dashboard

Trong bài viết này, mình sẽ hướng dẫn cài đặt Metallb và Ingress Nginx trên Kubernetes cluster On-premises

Metallb

MetalLB là một phần mềm cân bằng tải mạng cho các cụm Kubernetes không chạy trên cloud (bare metal Kubernetes clusters), sử dụng các giao thức định tuyến tiêu chuẩn.

Thông thường, khi cài đặt Kubernetes trên thiết bị của bạn (latop, bare metal server,…) thì chúng ta thường sử dụng NodePort service để truy cập vào app được deploy trên K8s. Nếu muốn sử dụng Serivice LoadBalancer thì chúng ta cần sử dụng các dich vụ cloud như Google Cloud, Azure, AWS,…

Metallb ra đời cung cấp giải pháp cho chúng ta có thể sử dụng LoadBalancer trên Bare metal K8s cluster. Hiện tại project mới ở giai đoạn beta nên chủ yếu chúng ta sử dụng ở môi trường dev/staging.

Ingress Nginx

Ingress Nginx là một Ingress controller cho Kubernetes sử dụng NGINX như một reverse proxy và load balancer. Ingress là một tài nguyên trong Kubernetes cho phép quản lý các kết nối đến các dịch vụ trong Kubernetes cluster. Ingress Nginx hỗ trợ khả năng căn bằng tải, SSL, URI rewrite và nhiều tính năng khác.

Thường thì Ingress Nginx mình sử dụng để cho phép bên ngoài truy cập vào ứng dụng thông qua tên miền ví dụ như: app1.example.com, app2.example.com.

NodePort

Trên bare metal K8s thì Ingress được deploy ở chế đó NodePort (Xem thêm tại đây), khi chúng ta kiểm tra thì sẽ thấy dạng như sau:

kubectl get services -n ingress-nginx
NAME                                 TYPE           CLUSTER-IP       EXTERNAL-IP    PORT(S)                      AGE
ingress-nginx-controller             NodePort       10.108.142.179   <none>         80:30882/TCP,443:32446/TCP   2d7h
ingress-nginx-controller-admission   ClusterIP      10.96.102.236    <none>         443/TCP                      2d7h

Chúng ta có thể thấy 2 port 80/443 trên Nginx được map tương ứng sang port 30882/32446, như vậy nếu muốn access vào App1 trên K8s thông qua Ingress Nginx thì cần truy cập như sau:

Như vậy khá là bất tiện, chúng ta có thể:

  • Dùng chức năng port-forward trên router để mapping tiếp port 80->30882 và 443->32446. Về cơ bản đường đi của nó như sau: Internet (80/http) –>router (port-forward) –> Kuberentes IP (30882/http) –> Nginx (80/http)
  • Dùng 1 Proxy như Haproxy hoặc Nginx đứng trước K8s cluster để điều phối. Chi tiết mình sẽ không trình bày

Để tránh những phức tạp khi triển khai Ingress Nginx trên Bare metal K8s cluster, dưới đây mình sẽ giới thiệu cách triển khai Metallb và Ingress Nginx (Load Balancer)

Metallb + Ingress Nginx

Dưới đây là sơ đồ hệ thống sẽ triển khai

Đầu tiên chúng ta deploy Metallb:

kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.9/config/manifests/metallb-native.yaml

Tiếp theo, chúng ta cần config dải IP sẽ cấp phát cho Metallb, tạo file config.yaml với nội dung dưới đây:

apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: default-pool
  namespace: metallb-system
spec:
  addresses:
    - 192.168.1.50/32
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: default
  namespace: metallb-system
spec:
  ipAddressPools:
    - default-pool

Trong trường hợp của mình, do chỉ để học tập, nghiên cứu nên mình chỉ set IP Pool có duy nhất 1 IP, Sau đó chúng ta apply thiết lập này cho Metallb

kubectl apply -f config.yaml

Kiểm tra xem resouce đã được deploy thành công chưa:

kubectl get all -n metallb-system
NAME                              READY   STATUS    RESTARTS        AGE
pod/controller-68bf958bf9-d7zrx   1/1     Running   2 (3d10h ago)   3d23h
pod/speaker-mhz86                 1/1     Running   2 (3d10h ago)   3d23h
pod/speaker-np7bv                 1/1     Running   2 (3d10h ago)   3d23h
pod/speaker-q7bcx                 1/1     Running   1 (3d10h ago)   3d23h

NAME                      TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
service/webhook-service   ClusterIP   10.106.251.1   <none>        443/TCP   3d23h

NAME                     DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
daemonset.apps/speaker   3         3         3       3            3           kubernetes.io/os=linux   3d23h

NAME                         READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/controller   1/1     1            1           3d23h

NAME                                    DESIRED   CURRENT   READY   AGE
replicaset.apps/controller-68bf958bf9   1         1         1       3d23h

Như vậy chúng ta đã có 1 LoadBalancer service cho Kubernetes cluster của mình, bước tiếp theo là deploy Nginx

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.7.0/deploy/static/provider/cloud/deploy.yaml

Kiểm tra xem các resouce của ingress nginx đã được triển khai chưa

kubectl get all -n ingress-nginx
NAME                                            READY   STATUS      RESTARTS        AGE
pod/ingress-nginx-admission-create-lsb4v        0/1     Completed   0               3d23h
pod/ingress-nginx-admission-patch-fjz79         0/1     Completed   0               3d23h
pod/ingress-nginx-controller-6bdb654777-p7dvf   1/1     Running     1 (3d10h ago)   3d23h

NAME                                         TYPE           CLUSTER-IP       EXTERNAL-IP    PORT(S)
 AGE
service/ingress-nginx-controller             LoadBalancer   10.108.142.179   192.168.1.50   80:30882/TCP,443:32446/TCP   3d23h
service/ingress-nginx-controller-admission   ClusterIP      10.96.102.236    <none>         443/TCP
 3d23h

NAME                                       READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/ingress-nginx-controller   1/1     1            1           3d23h

NAME                                                  DESIRED   CURRENT   READY   AGE
replicaset.apps/ingress-nginx-controller-6bdb654777   1         1         1       3d23h

NAME                                       COMPLETIONS   DURATION   AGE
job.batch/ingress-nginx-admission-create   1/1           29s        3d23h
job.batch/ingress-nginx-admission-patch    1/1           29s        3d23h

Như vậy chúng ta có thể thấy service/ingress-nginx-controller loại LoadBalancer đã được deploy thành công và External IP là 192.168.1.50

Bước tiếp theo chúng chúng ta phải cho phép bên ngoài truy cập vào địa chỉ IP 192.168.1.50

  • Nếu gói Internet của bạn có static IP (a.b.c.d)
    • Vào router cấu hình mở port 80/443 và forward traffic đến IP 192.168.1.50 hoặc có thể thêm IP 192.168.1.50 vào DMZ zone.
    • Bạn cần có tên miền mà trỏ đến IP a.b.c.d
  • Nếu gói Internet của bạn không có static IP
    • Vào router cấu hình mở port 80/443 và forward traffic đến IP 192.168.1.50 hoặc có thể thêm IP 192.168.1.50 vào DMZ zone.
    • Đăng ký DDNS (Dynamic Domain Name System) để có được 1 domain trỏ đến local IP của bạn. VD: k8slab.ddns.net

Triển khai 1 ứng dụng đơn giản với thông tin trong

banana.yaml

kind: Pod
apiVersion: v1
metadata:
  name: banana-app
  namespace: fruit
  labels:
    app: banana
spec:
  containers:
    - name: banana-app
      image: hashicorp/http-echo
      args:
        - '-text=banana'
---
kind: Service
apiVersion: v1
metadata:
  name: banana-service
  namespace: fruit
spec:
  selector:
    app: banana
  ports:
    - port: 5678 # Default port for image
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: fruits
  namespace: fruit
spec:
  ingressClassName: nginx
  rules:
    - host: banana.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: banana-service
                port:
                  number: 5678

apple.yaml

kind: Pod
apiVersion: v1
metadata:
  name: apple-app
  namespace: fruit
  labels:
    app: apple
spec:
  containers:
    - name: apple-app
      image: hashicorp/http-echo
      args:
        - "-text=apple"
---
kind: Service
apiVersion: v1
metadata:
  name: apple-service
  namespace: fruit
spec:
  selector:
    app: apple
  ports:
    - port: 5678 # Default port for image
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: fruits
  namespace: fruit
spec:
  ingressClassName: nginx
  rules:
    - host: apple.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: apple-service
                port:
                  number: 5678

Deploy app:

kubectl create namespace fruits
kubectl apply -f apple.yaml
kubectl apply -f banana.yaml