Table of contents
- Kiến trúc Ingress & Nginx Ingress Controller
- Nginx Ingress Controller Kubernetes Manifests
- Triển khai Nginx Ingress Controller qua các manifest
- Sự cần thiết của Admission Controller và Validating Webhook
- Tạo một namespace
- Tạo Admission Controller Roles và Service Account
- Tạo cấu hình Validating Webhook
- Triển khai các jobs để cập nhật webhook certificate
- Tạo Ingress Controller Roles và Service Account
- Tạo Configmap
- Tạo Ingress Controller và Admission Controller Services
- Tạo Ingress Controller Deployment
- Map Domain Name tới Ingress Loadbalancer IP
- Triển khai một ứng dụng demo
- Tạo Ingress Object cho ứng dụng
- TLS với Nginx Ingress
- Kết luận
Trong bài viết này ta sẽ học cách cài đặt Nginx Ingress Controller trên Kubernetes và cách cấu hình ingress sử dụng DNS.
Có hai loại Nginx Ingress Controller:
We will be using the kubernetes community Nginx controller. Ta sẽ sử dụng phiên bản đầu tiên.
Kiến trúc Ingress & Nginx Ingress Controller
Đây là kiến trúc cơ bản của Kubernetes Ingress sử dụng Nginx controller.
Nginx Ingress Controller Kubernetes Manifests
Mọi Kubernetes manifest được sử dụng trong bài viết này sẽ ở Github repository này.
git clone https://github.com/techiescamp/nginx-ingress-controller
Đầu tiên ta sẽ tìm hiểu các object liên quan tới quá trình triển khai Nginx Controller. Sau đó ta sẽ triển khai bằng manifest hoặc Helm chart.
Triển khai controller như sau:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.1.1/deploy/static/provider/cloud/deploy.yaml
Triển khai Nginx Ingress Controller qua các manifest
Ta cần triển khai các object sau để Nginx Controller có thể hoạt động được:
ingress-nginx
namespaceService account/Roles/ClusterRoles cho Nginx admission controller
Kiểm tra cấu hình webhook
Các job để tạo và update các webhook CA bundle.
Service account/Roles/ClusterRoles cho Nginx controller deployment
Nginx controller configmap
Các service cho nginx controller và admission controller
Ingress controller deployment
Sự cần thiết của Admission Controller và Validating Webhook
Kubernetes Admission Controller là một đoạn code dùng để kiểm tra hoặc cập nhật các object trước khi tạo chúng. Trong ingress controller, admission controller được dùng để kiểm tra các ingress object. Admission controller code là một phầ của Nginx controller nghe tại port 8443.
Tại sao ta cần admission controller?
Nếu không có admission controller, bạn có thể triển khai ingress object có thể chứa các cấu hình sai. Cấu hình sai có thể dẫn đến lỗi toàn bộ rule liên quan đến Ingress Controller đó.
Với admission controller, ta có thể đảm bảo ingress object ta tạo có cấu hình chính xác và sẽ không làm hỏng routing rule.
Đây là cách admission controller hoạt động cho Nginx:
Khi triển khai một ingress YAML, admission sẽ chặn request để kiểm tra.
Kubernetes API gửi ingress object tới admission controller endpoint dựa trên các admission webhook endpoint.
Sau đó nó gửi request tới Nginx deployment trên port 8443 để kiểm tra ingress object.
Admission controller gửi response tới Kubernetes API.
Nếu nó là một response hợp lệ thì API sẽ tạo Ingress Object.
Tạo một namespace
Ta sẽ triển khai Nginx controller trong namespace ingress-nginx
:
kubectl create ns ingress-nginx
Tạo Admission Controller Roles và Service Account
Ta cần một Role và ClusterRole với các quyền cần thiết và bind tới ingress-nginx-admission
service account.
Tạo admission-service-account.yaml
:
---
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-admission
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
annotations:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-admission
namespace: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- secrets
verbs:
- get
- create
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-admission
namespace: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: ingress-nginx-admission
subjects:
- kind: ServiceAccount
name: ingress-nginx-admission
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-admission
rules:
- apiGroups:
- admissionregistration.k8s.io
resources:
- validatingwebhookconfigurations
verbs:
- get
- update
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-admission
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: ingress-nginx-admission
subjects:
- kind: ServiceAccount
name: ingress-nginx-admission
namespace: ingress-nginx
Triển khai manifest:
kubectl apply -f admission-service-account.yaml
Tạo cấu hình Validating Webhook
Tạo validating-webhook.yaml
:
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-admission
webhooks:
- admissionReviewVersions:
- v1
clientConfig:
service:
name: ingress-nginx-controller-admission
namespace: ingress-nginx
path: /networking/v1/ingresses
failurePolicy: Fail
matchPolicy: Equivalent
name: validate.nginx.ingress.kubernetes.io
rules:
- apiGroups:
- networking.k8s.io
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- ingresses
sideEffects: None
Tạo ValidatingWebhookConfiguration
:
kubectl apply -f validating-webhook.yaml
Triển khai các jobs để cập nhật webhook certificate
ValidatingWebhookConfiguration
chỉ hoạt động thông qua HTTPS. Vì vậy nó cần CA bundle.
Ta dùng kube-webhook-certgen để tạo CA cert bundle với job đầu tiên. CA cert đã được tạo sẽ được lưu trong secret tên là ingress-nginx-admission
Job thứ hai patch ValidatingWebhookConfiguration
với CA bundle.
Tạo jobs.yaml
:
---
apiVersion: batch/v1
kind: Job
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-admission-create
namespace: ingress-nginx
spec:
template:
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-admission-create
spec:
containers:
- args:
- create
- --host=ingress-nginx-controller-admission,ingress-nginx-controller-admission.$(POD_NAMESPACE).svc
- --namespace=$(POD_NAMESPACE)
- --secret-name=ingress-nginx-admission
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.1.1
imagePullPolicy: IfNotPresent
name: create
securityContext:
allowPrivilegeEscalation: false
nodeSelector:
kubernetes.io/os: linux
restartPolicy: OnFailure
securityContext:
runAsNonRoot: true
runAsUser: 2000
serviceAccountName: ingress-nginx-admission
---
apiVersion: batch/v1
kind: Job
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-admission-patch
namespace: ingress-nginx
spec:
template:
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-admission-patch
spec:
containers:
- args:
- patch
- --webhook-name=ingress-nginx-admission
- --namespace=$(POD_NAMESPACE)
- --patch-mutating=false
- --secret-name=ingress-nginx-admission
- --patch-failure-policy=Fail
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.1.1
imagePullPolicy: IfNotPresent
name: patch
securityContext:
allowPrivilegeEscalation: false
nodeSelector:
kubernetes.io/os: linux
restartPolicy: OnFailure
securityContext:
runAsNonRoot: true
runAsUser: 2000
serviceAccountName: ingress-nginx-admission
Sau khi các job được thực thi bạn có thể describe ValidatingWebhookConfigurationand
để thấy patched bundle.
kubectl describe ValidatingWebhookConfiguration ingress-nginx-admission
Tạo Ingress Controller Roles và Service Account
Tạo ingress-service-account.yaml
:
---
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx
namespace: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- namespaces
verbs:
- get
- apiGroups:
- ""
resources:
- configmaps
- pods
- secrets
- endpoints
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses/status
verbs:
- update
- apiGroups:
- networking.k8s.io
resources:
- ingressclasses
verbs:
- get
- list
- watch
- apiGroups:
- ""
resourceNames:
- ingress-controller-leader
resources:
- configmaps
verbs:
- get
- update
- apiGroups:
- ""
resources:
- configmaps
verbs:
- create
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx
namespace: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: ingress-nginx
subjects:
- kind: ServiceAccount
name: ingress-nginx
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- configmaps
- endpoints
- nodes
- pods
- secrets
- namespaces
verbs:
- list
- watch
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- apiGroups:
- networking.k8s.io
resources:
- ingresses/status
verbs:
- update
- apiGroups:
- networking.k8s.io
resources:
- ingressclasses
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: ingress-nginx
subjects:
- kind: ServiceAccount
name: ingress-nginx
namespace: ingress-nginx
Triển khai manifest:
kubectl apply -f ingress-service-account.yaml
Tạo Configmap
Với ConfigMap này, bạn có thể tùy chỉnh cài đăt của Nginx. Ví dụ bạn có thể đặt custom header và hầu hết các cài đặt của Nginx.
Tạo configmap.yaml
:
---
apiVersion: v1
data:
allow-snippet-annotations: "true"
kind: ConfigMap
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-controller
namespace: ingress-nginx
Triển khai ConfigMap:
kubectl apply -f configmap.yaml
Tạo Ingress Controller và Admission Controller Services
Tạo file services.yaml
:
---
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
externalTrafficPolicy: Local
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- appProtocol: http
name: http
port: 80
protocol: TCP
targetPort: http
- appProtocol: https
name: https
port: 443
protocol: TCP
targetPort: https
selector:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
type: LoadBalancer
---
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-controller-admission
namespace: ingress-nginx
spec:
ports:
- appProtocol: https
name: https-webhook
port: 443
targetPort: webhook
selector:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
type: ClusterIP
Triển khai service:
kubectl apply -f services.yaml
ingress-nginx-controller
tạo một LoadBalancer trong nền tảng cloud bạn đang triển khai.
Bạn có thể lấy load balancer IP/DNS sử dụng câu lệnh:
kubectl --namespace ingress-nginx get services -o wide -w ingress-nginx-controller
Tạo Ingress Controller Deployment
Tạo deployment.yaml
:
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
minReadySeconds: 0
revisionHistoryLimit: 10
selector:
matchLabels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
template:
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
spec:
containers:
- args:
- /nginx-ingress-controller
- --publish-service=$(POD_NAMESPACE)/ingress-nginx-controller
- --election-id=ingress-controller-leader
- --controller-class=k8s.io/ingress-nginx
- --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
- --validating-webhook=:8443
- --validating-webhook-certificate=/usr/local/certificates/cert
- --validating-webhook-key=/usr/local/certificates/key
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: LD_PRELOAD
value: /usr/local/lib/libmimalloc.so
image: k8s.gcr.io/ingress-nginx/controller:v1.1.1
imagePullPolicy: IfNotPresent
lifecycle:
preStop:
exec:
command:
- /wait-shutdown
livenessProbe:
failureThreshold: 5
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
name: controller
ports:
- containerPort: 80
name: http
protocol: TCP
- containerPort: 443
name: https
protocol: TCP
- containerPort: 8443
name: webhook
protocol: TCP
readinessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
resources:
requests:
cpu: 100m
memory: 90Mi
securityContext:
allowPrivilegeEscalation: true
capabilities:
add:
- NET_BIND_SERVICE
drop:
- ALL
runAsUser: 101
volumeMounts:
- mountPath: /usr/local/certificates/
name: webhook-cert
readOnly: true
dnsPolicy: ClusterFirst
nodeSelector:
kubernetes.io/os: linux
serviceAccountName: ingress-nginx
terminationGracePeriodSeconds: 300
volumes:
- name: webhook-cert
secret:
secretName: ingress-nginx-admission
Tạo deployment:
kubectl apply -f deployment.yaml
Kiểm tra trạng thái pod:
kubectl get pods -n ingress-nginx
Map Domain Name tới Ingress Loadbalancer IP
The primary goal of Ingress is to receive external traffic to services running on Kubernetes. Ideally in projects, a DNS would be mapped to the ingress controller Loadbalancer IP.
Mục tiêu chính của Ingress là nhận các traffic bên ngoài tới các dịch vụ trong Kubernetes. Lý tưởng nhất là trong các dự án, DNS sẽ được ánh xạ tới IP Loadbalancer của ingress controller.
Single DNS Mapping
You can map a single domain directly as an A record to the load balancer IP. Using this you can have only one domain for the ingress controller and multiple path-based traffic routing.
Bạn có thể map một domain trực tiếp như một A record tới load balancer IP. Sử dụng cách này bạn sẽ chỉ có một domain cho Ingress Controller và nhiều path-based traffic routing.
Ví dụ:
www.example.com --> Loadbalancer IP
Bạn có thể có nhiều path-based traffic routing.
Ví dụ
http://www.example.com/app1
http://www.example.com/app2
http://www.example.com/app1/api
http://www.example.com/app2/api
Wildcard DNS Mapping
Nếu map một wildcard DNS tới load balancer, bạn có thể có DNS endpoint linh hoạt thông qua Ingress.
Khi đã thêm wildcard entry vào DNS record, bạn cần phải mention DNS cần thiết trong Ingress object sau đó Nginx Ingress controller sẽ đảm nhiệm việc route nó tới endpoint cần thiết.
Ví dụ:
*.example.com --> Loadbalancer IP
*.apps.example.com --> Loadbalancer IP
path-based routing:
#URL one
http://demo1.example.com/api
http://demo1.example.com/api/v1
http://demo1.example.com/api/v2
#app specific urls
http://grafana.apps.example.com
http://prometheus.apps.example.com
#URL two
http://demo2.apps.example.com/api
http://demo2.apps.example.com/api/v1
http://demo2.apps.example.com/api/v2
Để demo, mình đã map một wildcard DNS tới LoadBalancer IP. Dựa trên nhà cung cấp DNS của bạn, bạn có thể thêm DNS record.
Ảnh dưới đây hiển thị DNS record mình đã dùng cho demo này. Mình dùng EKS nên thay vì LoadBalancer IP thì mình có DNS của network load balancer endpoint - là một CNAME.
Triển khai một ứng dụng demo
For testing ingress, we will deploy a demo application and add a ClusterIp service to it. This application will be accessible only within the cluster without ingress.
Để kiểm tra Ingress, ta sẽ triển khai một ứng dụng demo và thêm ClusterIP service cho nó. Ứng dụng này sẽ chỉ có thể truy cập trong cụm mà không có Ingress.
- Tạo
dev
namespace:
kubectl create namespace dev
- Tạo
hello-app.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-app
namespace: dev
spec:
selector:
matchLabels:
app: hello
replicas: 3
template:
metadata:
labels:
app: hello
spec:
containers:
- name: hello
image: "gcr.io/google-samples/hello-app:2.0"
- Tạo deployment:
kubectl create -f hello-app.yaml
Kiểm tra trạng thái deployment:
kubectl get deployments -n dev
- Tạo
hello-app-service.yaml
apiVersion: v1
kind: Service
metadata:
name: hello-service
namespace: dev
labels:
app: hello
spec:
type: ClusterIP
selector:
app: hello
ports:
- port: 80
targetPort: 8080
protocol: TCP
- Tạo service:
kubectl create -f hello-app-service.yaml
Tạo Ingress Object cho ứng dụng
Giờ hãy tạo Ingress object để truy cập ứng dụng thông qua DNS.
- Tạo
ingress.yaml
:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress
namespace: dev
spec:
ingressClassName: nginx
rules:
- host: "demo.apps.mlopshub.com"
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: hello-service
port:
number: 80
- Describe ingress object để kiểm tra cấu hình
kubectl describe ingress -n dev
Giờ nếu truy cập demo.apps.mlopshub.com
ta sẽ có thể truy cập hello app. (Hãy thay domain của bạn vào nhé).
TLS với Nginx Ingress
You can configure TLS certificates with each ingress object. The TLS gets terminated at the ingress controller level.
Bạn có thể cấu hình TLS certificate với từng Ingress object. TLS sẽ bị terminate ở level Ingress Controller.
Kết luận
Ta đã học về cách cài đặt Nginx Ingress Controller.
Với Nginx controller configmap, bạn có thể cấu hình mọi cài đặt của Nginx mà không cần deploy lại controller.