Giải quyết lỗi Kubernetes Load Balancer External IP luôn ở trạng thái Pending
Vấn đề:
Trạng thái IP external của Kubernetes Load Balancer bị giữ ở trạng thái Pending là một vấn đề thường gặp trong các standalone clusters khi triển khai load balancer service.
Thực ra, đây là tính năng chứ không phải là bug. Khi sử dụng nhà cung cấp cloud như GCP, AWS hay Azure thì chính nhà cung cấp Cloud sẽ chỉ định external ip cho load balancer service. Nhưng cứ mỗi ip họ sẽ tính thêm phí
Cách giải quyết:
MetalLB có thể được sử dụng để giải quyết vấn đề này. MetalLB là một triển khai cân bằng tải cho các cụm bare metal Kubernetes clusters, sử dụng các giao thức định tuyến tiêu chuẩn. Metal LB sẽ được định cấu hình bên trong cụm Kubernetes nơi chúng ta đang làm việc.
Thông tin thêm về metallb: metallb.universe.tf
Cách thực hiện:
Deploy MetalLB Load Balancer trong K8s cluster:
Trước tiên, đảm bảo rằng không có vấn đề gì với việc sử dụng K8s cluster API và kubectl:
kubectl cluster-info
Cài đặt wget và curl:
### Debian / Ubuntu ###
sudo apt update && sudo apt install wget curl -y
### CentOS / RHEL / Fedora ###
sudo yum -y install wget curl
Download MetalLB installation manifest:
Lấy release tag mới nhất:
MetalLB_RTAG=$(curl -s https://api.github.com/repos/metallb/metallb/releases/latest|grep tag_name|cut -d '"' -f 4|sed 's/v//')
Kiểm tra release tag:
echo $MetalLB_RTAG
Tạo thư mục để download manifest:
mkdir ~/metallb
cd ~/metallb
Tải manifest mới nhất:
wget https://raw.githubusercontent.com/metallb/metallb/v$MetalLB_RTAG/config/manifests/metallb-native.yaml
Có 2 thành phần chính trong file manifest là:
metallb-system/controller deployment: Bộ điều khiển toàn cụm xử lý việc gán địa chỉ IP.
metallb-system/speaker daemonset
Cài đặt MetalLB Load Balancer trên cụm K8s:
kubectl apply -f metallb-native.yaml
Command trên sẽ giúp chúng ta deploy MetalLB trên cụm K8s trong namespace metallb-system
watch kubectl get all -n metallb-system
kubectl get pods -n metallb-system --watch
Đợi một lúc để mọi thứ chuyển sang trạng thái running. Lúc này, bạn có thể list các running Pods:
kubectl get pods -n metallb-system
Để list tất cả các service:
kubectl get all -n metallb-system
installation manifest không bao gồm tệp cấu hình cần thiết để sử dụng MetalLB. Tất cả các thành phần MetalLB đều được khởi động nhưng sẽ vẫn ở trạng thái không hoạt động cho đến khi bạn hoàn tất các cấu hình cần thiết.
Tạo Load Balancer services IP address pool:
MetalLB cần một nhóm địa chỉ IP để gán cho các dịch vụ khi nhận được yêu cầu đó. Chúng ta phải hướng dẫn MetalLB thực hiện việc đó thông qua IPAddressPool CR.
Hãy tạo một tệp có cấu hình cho IP mà MetalLB sử dụng để gán IP cho các dịch vụ. Trong cấu hình nhóm có dải IP 192.168.1.30-192.168.1.50.
vim ~/metallb/ipaddress_pools.yaml
Nội dung file:
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: production
namespace: metallb-system
spec:
addresses:
- 192.168.1.30-192.168.1.50
Địa chỉ IP có thể được xác định bằng CIDR, theo phạm vi và có thể chỉ định cả địa chỉ IPV4 và IPV6.
...
spec:
addresses:
- 192.168.1.0/24
Bạn có thể xác định nhiều IPAddressPool definition. Xem ví dụ dưới đây:
...
spec:
addresses:
- 192.168.1.0/24
- 172.20.20.30-172.20.20.50
- fc00:f853:0ccd:e799::/124
Announce service IPs sau khi tạo sau:
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: l2-advert
namespace: metallb-system
Sự quảng bá (advertisement) cũng có thể được giới hạn ở một Pool cụ thể. Trong ví dụ, giới hạn là đối với production pool.
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: pool1-advert
namespace: metallb-system
spec:
ipAddressPools:
- production
Cấu hình hoàn chỉnh với cả IP Address Pool và L2 advertisement:
vim ~/metallb/ipaddress_pools.yaml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: production
namespace: metallb-system
spec:
addresses:
- 192.168.1.30-192.168.1.50
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: l2-advert
namespace: metallb-system
kubectl apply -f ~/metallb/ipaddress_pools.yaml
kubectl get ipaddresspools.metallb.io -n metallb-system
kubectl get l2advertisements.metallb.io -n metallb-system
Xem chi tiết hơn:
kubectl describe ipaddresspools.metallb.io production -n metallb-system
Deploy services sử dụng MetalLB Load Balancer:
Với MetalLB được cài đặt và định cấu hình, chúng ta có thể kiểm tra bằng cách tạo service với spec.type được đặt thành LoadBalancer và MetalLB sẽ thực hiện phần còn lại. Điều này expose ra bên ngoài một service.
MetalLB attaches informational events vào các service mà nó đang kiểm soát. Nếu LoadBalancer của bạn hoạt động sai, hãy chạy kubectl describe service <tên service> và kiểm tra event log.
Chúng ta tạo một service test:
vim web-app-demo.yaml
apiVersion: v1
kind: Namespace
metadata:
name: web
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-server
namespace: web
spec:
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: httpd
image: httpd:alpine
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: web-server-service
namespace: web
spec:
selector:
app: web
ports:
- protocol: TCP
port: 80
targetPort: 80
type: LoadBalancer
kubectl apply -f web-app-demo.yaml
Kiểm tra địa chỉ IP được assigned bởi Load Balancer cho service:
kubectl get svc -n web
Test:
telnet 192.168.1.30 80
Request địa chỉ IP cụ thể cho 1 service:
MetalLB tôn trọng tham số spec.loadBalancerIP và tự động gán địa chỉ IP nhàn rỗi tiếp theo trong Pool. Nếu bạn muốn service của mình được thiết lập với một địa chỉ cụ thể, bạn có thể yêu cầu địa chỉ đó bằng cách đặt tham số này.
Xóa các resources cũ để thay thế bằng resources mới:
kubectl delete -f web-app-demo.yaml
vim web-app-demo.yaml
apiVersion: v1
kind: Namespace
metadata:
name: web
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-server
namespace: web
spec:
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: httpd
image: httpd:alpine
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: web-server-service
namespace: web
spec:
selector:
app: web
ports:
- protocol: TCP
port: 80
targetPort: 80
type: LoadBalancer
loadBalancerIP: 192.168.1.35
Apply configure để tạo ra Pods và Service endpoints:
kubectl apply -f web-app-demo.yaml
Kiểm tra IP được assigned:
kubectl get svc -n web
Test service:
curl http://192.168.1.35
Chọn pool địa chỉ IP cụ thể:
Khi tạo một service type là LoadBalancer, bạn có thể yêu cầu một nhóm địa chỉ IP cụ thể. Đây là một tính năng được MetalLB hỗ trợ.
Bạn có thể yêu cầu một nhóm cụ thể IP address assignment bằng cách thêm annotation metallicb.universe.tf/address-pool vào service, với tên của nhóm địa chỉ làm annotation value. Ví dụ:
apiVersion: v1
kind: Service
metadata:
name: web-server-service
namespace: web
annotations:
metallb.universe.tf/address-pool: production
spec:
selector:
app: web
ports:
- protocol: TCP
port: 80
targetPort: 80
type: LoadBalancer
Kiểm soát automatic address allocation:
Đây là một ứng dụng hợp lý dành cho nhóm IP “đắt tiền” nhỏ hơn (ví dụ: địa chỉ IPv4 public được thuê).
Theo mặc định, MetalLB phân bổ địa chỉ IP nhàn rỗi từ bất kỳ nhóm địa chỉ nào được configured. Hành vi này có thể được ngăn chặn bằng cách vô hiệu hóa phân bổ tự động cho một nhóm bằngflag autoAssign được đặt thành false:
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: expensive
namespace: metallb-system
spec:
addresses:
- 42.175.26.64/30
autoAssign: false
Các địa chỉ vẫn có thể được phân bổ cụ thể từ nhóm “đắt tiền” bằng các phương pháp được mô tả trong phần “Chọn pool địa chỉ IP cụ thể”.
Chia sẻ địa chỉ IP:
Theo mặc định, các service Kubernetes không chia sẻ địa chỉ IP. Đối với mọi nhu cầu định vị các dịch vụ trên một IP duy nhất, hãy thêm annotation metallicb.universe.tf/allow-shared-ip để cho phép chia sẻ IP có chọn lọc cho các service của bạn.
Giá trị của annotation này là “sharing key”. Để Services chia sẻ địa chỉ IP, phải đáp ứng các điều kiện sau:
- Cả hai services nên chia sẻ cùng một sharing key.
- Các services nên sử dụng các cổng khác nhau (ví dụ: tcp/80 cho một cổng và tcp/443 cho cổng còn lại).
- Hai services nên sử dụng Cluster external traffic policy hoặc cả hai đều trỏ đến cùng một nhóm các pods (tức là pod selectors giống hệt nhau).
Bằng cách sử dụng spec.loadBalancerIP, điều đó có nghĩa là hai service chia sẻ một địa chỉ cụ thể. Xem cấu hình ví dụ bên dưới của hai service chung địa chỉ IP:
apiVersion: v1
kind: Service
metadata:
name: dns-service-tcp
namespace: demo
annotations:
metallb.universe.tf/allow-shared-ip: "key-to-share-192.168.1.36"
spec:
type: LoadBalancer
loadBalancerIP: 192.168.1.36
ports:
- name: dnstcp
protocol: TCP
port: 53
targetPort: 53
selector:
app: dns
---
apiVersion: v1
kind: Service
metadata:
name: dns-service-udp
namespace: demo
annotations:
metallb.universe.tf/allow-shared-ip: "key-to-share-192.168.1.36"
spec:
type: LoadBalancer
loadBalancerIP: 192.168.1.36
ports:
- name: dnsudp
protocol: UDP
port: 53
targetPort: 53
selector:
app: dns
Xem thêm các cấu hình L2 nâng cao:
metallb.universe.tf/configuration/_advanced..
Đặt Nginx sử dụng MetalLB:
Nếu bạn đang sử dụng Nginx Ingress Controller trong cluster, bạn có thể định cấu hình nó để sử dụng MetalLB làm Bộ cân bằng tải.
Deploy Nginx Ingress Controller trên K8s sử dụng Helm chart:
Sử dụng service là cách thông thường để expose các ứng dụng đang chạy trên một nhóm Pod trong Cụm Kubernetes. Trong Kubernetes, mỗi Pod có địa chỉ IP riêng nhưng một nhóm Pod có thể chia sẻ tên DNS. Kubernetes có thể truyền bá dữ liệu ra khắp các Pod mà không cần thay đổi lớp ứng dụng. Theo mặc định, một service được cấp một địa chỉ IP (đôi khi được gọi là “cluster IP“), được sử dụng bởi các proxy của Service. Label selectors cho phép Service tìm ra Pod nào trong một nhóm.
Ingress Controller là gì?
Theo tài liệu chính thống của Kubernetes:
An API object that manages external access to the services in a cluster, typically HTTP.
Ingress may provide load balancing, SSL termination and name-based virtual hosting.
Một Ingress trong Kubernetes expose các HTTP và HTTPS routes từ bên ngoài cụm đến các service chạy trong cụm. Tất cả việc định tuyến lưu lượng truy cập được kiểm soát bởi các quy tắc được xác định trên Ingress resource. Một Ingress có thể được cấu hình để:
Cung cấp Service với các URL có thể truy cập được từ bên ngoài
Cân bằng tải traffic đi vào các cluster services
Terminate SSL / TLS traffic
Cung cấp name-based virtual hosting trong Kubernetes
Ingress controller là thứ fulfils Ingress, thường là với bộ cân bằng tải. Dưới đây là ví dụ về cách Ingress gửi tất cả lưu lượng truy cập của máy khách đến Service trong Cụm Kubernetes:
Với các traffic HTTP và HTTPS tiêu chuẩn, một Ingress Controller sẽ được configured để listen ở các port 80 và 443. Nó sẽ bind với một địa chỉ IP mà cluster sẽ nhận được lưu lượng truy cập từ đó. Wildcard DNS đại diện cho domain được sử dụng cho các Ingress routes sẽ trỏ đến (các) địa chỉ IP mà Ingress routes listen.
Thực tế là Kubernetes áp dụng cách tiếp cận BYOS (Bring-Your-Own-Software) cho hầu hết các addons của nó và nó không cung cấp phần mềm thực hiện các chức năng Ingress. Bạn có thể chọn từ rất nhiều Ingress Controllers có sẵn.
Step 1: Cài đặt Nginx Ingress Controller:
Option 1: Install không dùng Helm
Với cách này, bạn sẽ cần phải download và chạy tay deployment manifest sử dụng câu lệnh kubectl.
Cài đặt git, curl và wget:
# CentOS / RHEL / Fedora / Rocky
sudo yum -y install wget curl git
# Debian / Ubuntu
sudo apt update
sudo apt install wget curl git
Apply Nginx Ingress Controller manifest:
Bài viết này tập trung vào sử dụng Bare-metal Nginx Ingress deployment, nếu sử dụng các managed cluster, xem các tài liệu sau:
Phương pháp Bare-metal áp dụng cho mọi cụm Kubernetes được triển khai trên bare-metal với bản phân phối Linux chung (chẳng hạn như CentOS, Ubuntu, Debian, Rocky Linux), v.v.
Download Nginx controller deployment:
controller_tag=$(curl -s https://api.github.com/repos/kubernetes/ingress-nginx/releases/latest | grep tag_name | cut -d '"' -f 4)
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/${controller_tag}/deploy/static/provider/baremetal/deploy.yaml
mv deploy.yaml nginx-ingress-controller-deploy.yaml
kubectl apply -f nginx-ingress-controller-deploy.yaml
kubectl config set-context --current --namespace=ingress-nginx
kubectl get pods -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx --watch
Nếu bạn muốn chạy nhiều Nginx Ingress Pods, bạn có thể mở rộng quy mô bằng lệnh bên dưới:
kubectl -n ingress-nginx scale deployment ingress-nginx-controller --replicas 2
Option 3: Sử dụng Helm:
Cài đặt helm 3:
cd ~/
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3
chmod 700 get_helm.sh
./get_helm.sh
helm version
Download latest stable release of Nginx Ingress Controller:
controller_tag=$(curl -s https://api.github.com/repos/kubernetes/ingress-nginx/releases/latest | grep tag_name | cut -d '"' -f 4)
wget https://github.com/kubernetes/ingress-nginx/archive/refs/tags/${controller_tag}.tar.gz
Giải nén:
tar xvf ${controller_tag}.tar.gz
Vào thư mục:
cd ingress-nginx-${controller_tag}
cd charts/ingress-nginx/
Tạo namespace:
kubectl create namespace ingress-nginx
Deploy nginx ingress control:
helm install -n ingress-nginx ingress-nginx -f values.yaml .
Sample output:
NAME: ingress-nginx
LAST DEPLOYED: Thu Nov 4 02:50:28 2021
NAMESPACE: ingress-nginx
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
The ingress-nginx controller has been installed.
It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status by running 'kubectl --namespace ingress-nginx get services -o wide -w ingress-nginx-controller'
An example Ingress that makes use of the controller:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
name: example
namespace: foo
spec:
ingressClassName: example-class
rules:
- host: www.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: exampleService
port: 80
# This section is only required if TLS is to be enabled for the Ingress
tls:
- hosts:
- www.example.com
secretName: example-tls
If TLS is enabled for the Ingress, a Secret containing the certificate and key must also be provided:
apiVersion: v1
kind: Secret
metadata:
name: example-tls
namespace: foo
data:
tls.crt: <base64 encoded cert>
tls.key: <base64 encoded key>
type: kubernetes.io/tls
Check status:
kubectl get all -n ingress-nginx
kubectl get pods -n ingress-nginx
kubectl -n ingress-nginx logs deploy/ingress-nginx-controller
kubectl -n ingress-nginx logs deploy/ingress-nginx-controller -f
Set replica count of the controller pods to 2:
$ vim values.yaml
controller:
replicaCount: 3
Confirm hiện tại chỉ có 1 pod:
kubectl -n ingress-nginx get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
ingress-nginx-controller 1/1 1 1 43m
Update ingress – nginx release:
helm upgrade -n ingress-nginx ingress-nginx -f values.yaml .
Check số lượng pod sau khi upgrade:
kubectl -n ingress-nginx get deploy
Uninstall the chart:
Để xóa nginx ingress controller và tất cả các tài nguyên liên quan mà chúng ta đã triển khai bởi Helm:
helm -n ingress-nginx uninstall ingress-nginx
Step 2: Configure Nginx Ingress Controller
Option 1: Sử dụng Load Balancer:
Setting Nginx Ingress dùng MetalLB:
Check nginx service:
kubectl get svc -n ingress-nginx
Nếu cụm Kubernetes của bạn là cụm “real” hỗ trợ các dịch vụ thuộc loại LoadBalancer, thì cụm đó sẽ phân bổ địa chỉ IP external hoặc FQDN cho bộ ingress controller. Sử dụng lệnh sau để xem địa chỉ IP hoặc FQDN đó:
kubectl get service ingress-nginx-controller --namespace=ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller NodePort 10.108.187.12 <none> 80:31320/TCP,443:31124/TCP 25m
Patch ingress-nginx-controller
service bằng cách đặt loại service thành LoadBalancer:
kubectl -n ingress-nginx patch svc ingress-nginx-controller --type='json' -p '[{"op":"replace","path":"/spec/type","value":"LoadBalancer"}]'
kiểm tra lại:
kubectl get service ingress-nginx-controller --namespace=ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller LoadBalancer 10.108.4.75 192.168.1.30 80:30084/TCP,443:30540/TCP 10m
Service được tự động gán một địa chỉ IP từ Nhóm địa chỉ như được định cấu hình trong MetalLB.
Mapping DNS name cho Nginx Ingress từ LB IP
Chúng ta có thể tạo tên miền, tốt nhất là wildcard để sử dụng khi tạo các tuyến Ingress trong Kubernetes. Trong cụm k8s, chúng ta có k8s.example.com làm tên miền cơ sở. Chúng ta sẽ sử dụng miền wildcard duy nhất *.k8s.example.com cho Ingress.
Mapping là *.k8s.example.com trỏ đến địa chỉ IP 192.168.1.30 (IP Nginx Ingress LB).
Option 2: Sử dụng nodes để chạy nginx Ingress Pod (không được khuyến khích)
- Label nodes sẽ sử dụng để chạy Ingress Controller Pods:
node selector được sử dụng khi chúng ta phải triển khai một nhóm hoặc một nhóm pods trên một nhóm nodes cụ thể đã vượt qua các tiêu chí được xác định trong tệp cấu hình.
Danh sách các nodes:
kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8smaster01.example.com Ready control-plane,master 14h v1.23.5
k8smaster02.example.com Ready control-plane,master 14h v1.23.5
k8sworker01.example.com Ready <none> 13h v1.23.5
k8sworker02.example.com Ready <none> 13h v1.23.5
k8sworker03.example.com Ready <none> 13h v1.23.5
2. Sửa ingress-nginx-controller service và set externalIPs
Trong quá trình thiết lậpprivate Infrastructure Kubernetes deployment, bạn khó có thể không có Load Balancer service support.
kubectl get svc -n ingress-nginx ingress-nginx-controller
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller NodePort 10.101.4.21 <none> 80:30248/TCP,443:30773/TCP 3m53s
Bạn sẽ nhận thấy service thuộc loại NodePort. Chúng ta sẽ cập nhật service bằng cách bind Ingress với địa chỉ IP cụ thể bằng cách sử dụng IP external.
Kubernetes hỗ trợ gán địa chỉ IP external cho trường Service spec.externalIPs thông qua ExternalIP facility. Điều này sẽ expose một địa chỉ IP ảo bổ sung, được gán cho Nginx Ingress Controller Service. Điều này cho phép chúng ta hướng lưu lượng truy cập đến một local node để cân bằng tải.
Trong Cụm Kubernetes của tôi, tôi có hai node control Plane nodes có địa chỉ IP chính bên dưới:
- k8smaster01.example.com – 192.168.42.245
- k8smaster02.example.com – 192.168.42.246
Địa chỉ IP của các nodes có thể được kiểm tra bằng cách chạy lệnh:
kubectl get nodes -o wide
Tôi sẽ tạo một tệp chứa sửa đổi để thêm External IPs vào service.
$ vim external-ips.yaml
spec:
externalIPs:
- 192.168.42.245
- 192.168.42.246
apply patch cho service:
kubectl -n ingress-nginx patch svc ingress-nginx-controller --patch "$(cat external-ips.yaml)"
kubectl get svc ingress-nginx-controller -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller NodePort 10.101.4.21 192.168.42.245,192.168.42.246 80:30248/TCP,443:30773/TCP 8m31
3. Chạy ingress-nginx-controller Pods trên Control Plane (Master) Nodes
Bạn có thể cân nhắc việc chạy Ingress Controller Pods trên các master nodes. Để đạt được điều này, chúng ta sẽ gắn nhãn các master nodes, sau đó sử dụng node selector để chỉ định các pods trong Ingress controller deployment cho các Control Plane nodes.
kubectl get nodes -l node-role.kubernetes.io/control-plane
NAME STATUS ROLES AGE VERSION
k8smaster01.example.com Ready control-plane,master 16d v1.23.5
k8smaster02.example.com Ready control-plane,master 16d v1.23.5
Thêm label runress=nginx vào các master nodes:
kubectl label node k8smaster01.example.com runingress=nginx
kubectl label node k8smaster02.example.com runingress=nginx
Labels đã add vào nodes có thể được check bằng câu lệnh:
kubectl describe node <node-name>
Ví dụ:
kubectl describe node k8smaster01.example.com
Name: k8smaster01.example.com
Roles: control-plane,master
Labels: beta.kubernetes.io/arch=amd64
beta.kubernetes.io/os=linux
kubernetes.io/arch=amd64
kubernetes.io/hostname=k8smaster01.example.com
kubernetes.io/os=linux
node-role.kubernetes.io/control-plane=
node-role.kubernetes.io/master=
node.kubernetes.io/exclude-from-external-load-balancers=
runingress=nginx # Label added
.....
Tạo patch file để chạy các pods trên nodes với label runingress=nginx:
vim node-selector-patch.yaml
spec:
template:
spec:
nodeSelector:
runingress: nginx
kubectl get deploy -n ingress-nginx
kubectl -n ingress-nginx patch deployment/ingress-nginx-controller --patch "$(cat node-selector-patch.yaml)"
4. Thêm tolerations cho phép Nginx ingress Pods chạy trên Control Plane nodes
Trong Kubernetes, default setting disable pods trong master nodes. Để các Ingress pods chạy trong các master nodes, bạn sẽ phải thêm tolerations.
Hãy tạo một file patch để áp dụng tolerations khi triển khai Ingress:
vim master-node-tolerations.yaml
spec:
template:
spec:
tolerations:
- key: node-role.kubernetes.io/master
operator: Equal
value: "true"
effect: NoSchedule
- key: node-role.kubernetes.io/master
operator: Equal
effect: NoSchedule
- key: node-role.kubernetes.io/control-plane
operator: Equal
value: "true"
effect: NoSchedule
- key: node-role.kubernetes.io/control-plane
operator: Equal
effect: NoSchedule
Apply the patch:
kubectl -n ingress-nginx patch deployment/ingress-nginx-controller --patch "$(cat master-node-tolerations.yaml)"
Confirm pod mới tạo có Node Selector configured:
kubectl get pods -n ingress-nginx
NAME READY STATUS RESTARTS AGE
ingress-nginx-admission-create--1-hpkzp 0/1 Completed 0 3d
ingress-nginx-admission-patch--1-qnjlj 0/1 Completed 1 3d
ingress-nginx-controller-57b46c846b-8n28t 1/1 Running 0 1m47s
$ kubectl describe pod ingress-nginx-controller-57b46c846b-8n28t
...omitted_output...
QoS Class: Burstable
Node-Selectors: kubernetes.io/os=linux
run-nginx-ingress=true
runingress=nginx
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
5. Update values.yml để thay đổi parameters (Chỉ khi sử dụng Helm deployment)
vim values.yaml
Thêm tolerations cho Master nodes
controller:
tolerations:
- key: node-role.kubernetes.io/master
operator: Equal
value: "true"
effect: NoSchedule
- key: node-role.kubernetes.io/master
operator: Equal
effect: NoSchedule
- key: node-role.kubernetes.io/control-plane
operator: Equal
value: "true"
effect: NoSchedule
- key: node-role.kubernetes.io/control-plane
operator: Equal
effect: NoSchedule
Set controller.service.externalIPs:
controller:
service:
externalIPs: ["192.168.42.245","192.168.42.246"]
Để set số lượng replicas Ingress controller deployment trong controller.replicaCount:
controller:
replicaCount: 1
Nếu sử dụng node selector cho pod assignment cho Ingress controller pods set on controller.nodeSelector
controller:
nodeSelector:
kubernetes.io/os: linux
runingress: "nginx"
Tạo namespace:
kubectl create namespace ingress-nginx
Deploy Nginx Ingress Controller:
helm install -n ingress-nginx ingress-nginx -f values.yaml .
Step 3: Deploy services test để test chức năng Nginx Ingress:
Tạo một namespace có tên là demo:
kubectl create namespace demo
Tạo test pod và services bằng file YAML:
cd ~/
vim demo-app.yml
kind: Pod
apiVersion: v1
metadata:
name: apple-app
labels:
app: apple
spec:
containers:
- name: apple-app
image: hashicorp/http-echo
args:
- "-text=apple"
---
kind: Service
apiVersion: v1
metadata:
name: apple-service
spec:
selector:
app: apple
ports:
- port: 5678 # Default port for image
---
kind: Pod
apiVersion: v1
metadata:
name: banana-app
labels:
app: banana
spec:
containers:
- name: banana-app
image: hashicorp/http-echo
args:
- "-text=banana"
---
kind: Service
apiVersion: v1
metadata:
name: banana-service
spec:
selector:
app: banana
ports:
- port: 5678 # Default port for image
kubectl apply -f demo-app.yml -n demo
Test hoạt động:
kubectl get pods -n demo
kubectl -n demo logs apple-app
Tạo Ubuntu pod sử dụng để test service connection:
cat <<EOF | kubectl -n demo apply -f -
apiVersion: v1
kind: Pod
metadata:
name: ubuntu
labels:
app: ubuntu
spec:
containers:
- name: ubuntu
image: ubuntu:latest
command: ["/bin/sleep", "3650d"]
imagePullPolicy: IfNotPresent
restartPolicy: Always
EOF
Test services connectivity trong namespace:
kubectl -n demo exec -ti ubuntu -- bash
root@ubuntu:/# apt update && apt install curl -y
root@ubuntu:/# curl apple-service:5678
apple
root@ubuntu:/# curl banana-service:5678
banana
Tạo ingress route:
Cách tạo Ingress definition có thể được xem bằng command sau:
kubectl explain ingress
Bây giờ, định nghĩa một Ingress để route request tới /apple kết nối tới service thứ nhất, và /banana tới service thứ hai. Kiểm tra Ingress’ rules field định nghĩa các request đi qua
vim webapp-app-ingress.yml
Với k8s cluster > 1.19:
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: webapp-ingress
spec:
ingressClassName: nginx
rules:
- host: webapp.k8s.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-server-service
port:
number: 80
kubectl -n web apply -f webapp-app-ingress.yml
List configured ingress:
kubectl get ingress -n web
Exec vào nginx ingress controller để xem nginx configuration đã được injected hay chưa
kubectl get pods -n ingress-nginx
NAME READY STATUS RESTARTS AGE
ingress-nginx-controller-6f5844d579-hwrqn 1/1 Running 0 53m
ingress-nginx-controller-6f5844d579-kvgtd 1/1 Running 0 25m
ingress-nginx-controller-6f5844d579-lcrrt 1/1 Running 0
kubectl exec -n ingress-nginx -it ingress-nginx-controller-6f5844d579-hwrqn -- /bin/bash
bash-5.1$ less /etc/nginx/nginx.conf
Test service sử dụng curl:
curl http://webapp.k8s.example.com/
<html><body><h1>It works!</h1></body></html>
Note:
Trong service phải thiết định spec thêm :
externalTrafficPolicy: Local
Thì app bên trong mới get được IP thật , vì bản chất thằng MetalLB này nó chỉ làm việc ở L2 nên việc get IP thật TCP HTTP hơi khoai