Bảo mật Nginx Ingress với Cert Manager trên Kubernetes
Hello các bạn, lại là mình đây 👋
Hi vọng các bạn vẫn hóng series của mình, và hi vọng rằng các bạn không nghĩ rằng mình sẽ bỏ rơi series này 🤣🤣
Vậy thì hôm nay ta hâm nóng lại series này với setup Nginx Ingress Controller, cert-manager để tự động việc lấy HTTPS trên K8S nhé
Lên tàu thôi ⛴️⛴️
Những thứ ta sẽ làm
Ở bài này ta sẽ deploy một Todo list app giống như của mình như sau:
Các bạn có thể truy cập ở đây: https://todo.jamesisme.com (source code cho bạn nào muốn xem: https://github.com/maitrungduc1410/todo-app)
App khá đơn giản với các thành phần như sau: 1 frontend, 1 backend, 1 DB MySQL
Ta sẽ deploy app trên K8S, setup Nginx Ingress, và lấy HTTPS bằng cert-manager nhé
Test thử ở local
Trước khi deploy thì luôn luôn phải chạy thử coi xem nó như thế nào đã nhỉ 😎😎
Các bạn tạo mới folder bất kì, trong đó tạo docker-compose.yml
:
version: '3.7'
services:
frontend:
image: maitrungduc1410/k8s-ingress-demo-frontend
restart: always
volumes:
- ./nginx.app.conf:/etc/nginx/conf.d/default.conf
ports:
- 3002:80
backend:
image: maitrungduc1410/k8s-ingress-demo-backend
restart: always
env_file: .env
db:
image: mysql:8
restart: always
environment:
MYSQL_DATABASE: ${DB_NAME}
MYSQL_USER: ${DB_USER}
MYSQL_PASSWORD: ${DB_PASSWORD}
MYSQL_ROOT_PASSWORD: rootpass
volumes:
- ./data:/var/lib/mysql/
Tạo tiếp cho mình file nginx.app.conf
:
server {
listen 80;
listen [::]:80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
location /api {
proxy_pass http://backend:3000;
proxy_redirect off;
proxy_http_version 1.1;
proxy_cache_bypass $http_upgrade;
proxy_set_header Host $host;
proxy_set_header Connection 'upgrade';
proxy_set_header Upgrade $http_upgrade;
proxy_set_header X-Real-Ip $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
Tiếp theo ta tạo .env
:
DB_HOST=db
DB_PORT=3306
DB_USER=myuser
DB_PASSWORD=myuserpass
DB_NAME=k8s_ingress
DATABASE_URL=mysql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME
Sau đó ta tạo folder data
để mount volume cho mysql nha:
mkdir data
Cuối cùng là ta start app:
docker compose up -d
Và mở trình duyệt ở http://localhost:3002
, các bạn tự kiểm tra xem app có lên ngon nghẻ không nhé 😂
Local oke rồi thì ta vào lý thuyết thôi nào 🥸🥸
Lý thuyết vỡ lòng
Ingress là gì?
Về cơ bản thì Ingress trong Kubernetes là một tài nguyên cho phép quản lý luồng lưu lượng truy cập đến các Service trong một Kubernetes clusler từ bên ngoài. Nó hoạt động như một cái traffic router, cho phép request từ bên ngoài được định tuyến đến các Service cụ thể trong cluster dựa trên cấu hình do ta định nghĩa.
Ingress làm cho việc quản lý traffic truy cập từ bên ngoài vào các ứng dụng trở nên dễ dàng hơn bằng cách giúp xác định các routing rules và cung cấp một cách thức để quản lý các routes.
Ta cùng xem ảnh dưới (mình lấy luôn trên trang chủ k8s vì nó khá dễ hiểu)
Ở trên các bạn thấy, traffic đi từ Client (bên ngoài) -> Load Balancer được managed (bởi cloud provider) -> Ingress (do ta định nghĩa), ở đó ta sẽ định nghĩa các routing rules -> vào Service -> cuối cùng là vào Pod
Ingress theo mình thấy thường dùng để expose Service của chúng ta ra ngoài bằng URL (domain) để friendly hơn, hoặc làm load balance traffic,...
Nhưng chú ý rằng Ingress nó không expose port nào cả, không giống như Service (type=NodePort) đâu nhé các bạn
Thường thì mỗi app sẽ có 1 Ingress riêng, dành cho 1 domain riêng, dùng 2 domain cho 1 app cũng được nhưng mà tuỳ trường hợp
Ingress Controller
Để mà Ingress mà chúng ta viết chạy được thì ta cần có Ingress Controller
Ingress Controller là một thành phần trong Kubernetes chịu trách nhiệm cho việc triển khai và quản lý các rules của Ingress. Ingress Controller làm nhiệm vụ xử lý request tới Ingress và thực hiện các hành động phù hợp, chẳng hạn như route request đến các Service cụ thể trong cluster. Mỗi loại Ingress Controller có thể có triển khai khác nhau, nhưng chức năng chính là nhận và xử lý các request tới Ingress, sau đó cấu hình các bản ghi tương ứng trong cơ sở dữ liệu của Cluster để đảm bảo việc routing traffic đến đúng nơi.
Ingress Controller thì có rất nhiều loại, ở đây mình sẽ dùng loại phổ biến nhất là Nginx Ingress Controller
Nãy giờ nói gì hơi khó hiểu à nha 🤔🤔🤔
Oke, Ví dụ, một Nginx Ingress Controller để triển khai các quy tắc Ingress do ta viết. Khi một yêu cầu HTTP đến, Ingress Controller sẽ đọc cấu hình Ingress, quyết định nơi mà yêu cầu đó cần được chuyển tới, và sau đó cấu hình máy chủ proxy (như Nginx) để đảm bảo request được định tuyến đúng cách.
Vẫn là bức ảnh bên trên thì Ingress Controller nó như thế này:
Một cluster có thể có 1 Ingress Controller dùng chung cho cả cluster, nhưng cũng có thể có nhiều Ingress Controller (ví dụ mỗi namespace 1 controller). Ở bài này thì ta sẽ dùng 1 controller cho cả cluster
Nếu các bạn vẫn thấy khó hiểu, Ingress Controller nó là cái gì thì ta tạm thời công nhận nó là 1 cái "gì đó" làm nhiệm vụ đọc cấu hình Ingress do ta viết và thực thi nhé
Và luôn ghi nhớ là Ingress khác Ingress Controller, ta cần dùng cho đúng khái niệm nhé
Giờ thì zô phần chính thôi nào 🚀🚀
Setup Ingress và Ingress Controller
Ingress Controller
Như mình đã nói ở phần trước, ta cần phải có Ingress Controller, tối thiểu 1 cluster 1 controller (như bài này mình làm). Ở bài này ta chọn Nginx Ingress Controller: https://kubernetes.github.io/ingress-nginx
Nhưng vì Ingress Controller setup rất phức tạp, và thường 1 cluster chỉ cần 1 cái controller thôi, nên mình đã làm luôn cho các bạn bước này, các bạn chỉ cần xem thôi , bước cài Nginx Ingress Controller này các bạn không cần làm nhé.
Việc mình làm thì rất đơn giản thôi, lên trang chủ của Nginx Ingress và tuỳ vào cloud provider của mình là gì mà chọn cho đúng:
Và ta chỉ cần kubectl apply
là được, phần còn lại đã có hết ở file YML của họ rồi
Đây là tất cả những gì có của nginx ingress controller sau khi ta apply:
Như ta thấy thì toàn bộ những thứ liên quan tới Nginx Ingress Controller được deploy ở 1 namespace riêng, cơ bản những thứ nó làm như sau:
- Có 1 Deployment chạy 1 con nginx
- có 1 service expose ra bên ngoài với type=LoadBalancer
- mọi request đi vào cluster đầu tiên sẽ qua con nginx này
- Controller này sẽ
watch
tất cả các namespace, và khi nào ta tạo/sửa Ingress nó sẽ tự update và reload.
Flow kiểu như sau:
Lấy session
Tiếp theo trước khi cầu hình Ingress thì ta cần phải deploy app demo của chúng ta trước đã nhé. Ta đầu tiên tạo 1 folder để chứa toàn bộ file manifest cho bài này nhé.
Sau đó vẫn như các bài trước ta cần phải lấy K8S Session để truy cập cluster của mình và thực hành. Các bạn nhớ check Require Domain
nhé, vì bài này ta làm với Ingress mà, ta cần có domain.
Sau khi lấy được file session về thì ta check thử xem domain của ta là gì nhé:
kubectl get pod --kubeconfig=./kubernetes-config
Ta sẽ thấy in ra là No resources found in lk8s-75b79a namespace.
Sau khi các bạn lấy session thì thông tin về namespace và domain của các bạn sẽ được hiển thị luôn:
Bước này các bạn phải chú ý thật kĩ domain của các bạn là gì và dùng nó xuyên suốt bài này nhé
Ở bài này ta sẽ có: frontend, backend và database (mysql). Nên tương ứng ta sẽ tạo file deployment và service. Và bởi vì ta chỉ cần frontend được expose ra bên ngoài, giao tiếp giữa frontend -> backend và backend -> DB, là internal trong cluster thôi.
Flow mà tí nữa ta deploy sẽ như sau:
Deploy app
Giờ ta tiến hành deploy app nhé.
Đầu tiên các bạn tạo cho mình file secret.yml
:
apiVersion: v1
kind: Secret
metadata:
name: todo
type: Opaque
stringData:
MYSQL_HOST: db
MYSQL_PORT: "80"
MYSQL_USER: myuser
MYSQL_PASSWORD: myuserpass
MYSQL_DATABASE: todo_app
DATABASE_URL: mysql://myuser:myuserpass@db:80/todo_app
MYSQL_ROOT_PASSWORD: rootpass
# Note: Cách bên dưới chạy trong Docker nhưng không chạy trên k8s
# DATABASE_URL: mysql://${MYSQL_USER}:${MYSQL_PASSWORD}@${MYSQL_HOST}:${MYSQL_PORT}/${MYSQL_DATABASE}
File này sẽ chứa secret dùng chung cho cả backend và db (mysql)
Sau đó ta apply
để tạo secret nhé:
kubectl apply -f secret.yml --kubeconfig=./kubernetes-config
Tiếp theo ta tạo file deployment.yml
:
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
labels:
app.kubernetes.io/name: k8s-ingress-demo-backend
spec:
selector:
matchLabels:
app: backend
template:
metadata:
labels:
app: backend
spec:
containers:
- name: backend
image: maitrungduc1410/k8s-ingress-demo-backend:latest
ports:
- containerPort: 3000
name: pod-http
resources:
requests:
memory: "128Mi"
cpu: "64m"
limits:
memory: "750Mi"
cpu: "500m"
envFrom:
- secretRef:
name: todo
---
apiVersion: v1
kind: Service
metadata:
name: backend
spec:
type: ClusterIP
ports:
- name: svc-http
protocol: TCP
port: 80
targetPort: pod-http
selector:
app: backend
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
labels:
app.kubernetes.io/name: k8s-ingress-demo-frontend
spec:
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: frontend
image: maitrungduc1410/k8s-ingress-demo-frontend:latest
ports:
- containerPort: 80
name: pod-http
resources:
requests:
memory: "128Mi"
cpu: "64m"
limits:
memory: "512Mi"
cpu: "200m"
---
apiVersion: v1
kind: Service
metadata:
name: frontend
spec:
type: LoadBalancer
ports:
- name: svc-http
protocol: TCP
port: 80
targetPort: pod-http
selector:
app: frontend
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: db
labels:
app.kubernetes.io/name: k8s-ingress-demo-db
spec:
selector:
matchLabels:
app: db
template:
metadata:
labels:
app: db
spec:
containers:
- name: db
image: mysql:8
ports:
- containerPort: 3306
name: pod-http
resources:
requests:
memory: "128Mi"
cpu: "64m"
limits:
memory: "750Mi"
cpu: "500m"
envFrom:
- secretRef:
name: todo
---
apiVersion: v1
kind: Service
metadata:
name: db
spec:
type: ClusterIP
ports:
- name: svc-http
protocol: TCP
port: 80
targetPort: pod-http
selector:
app: db
Ở trên mình dùng 1 file manifest và khai báo tất cả frontend, backend và db vào đó, mỗi cái gồm 1 deployment và 1 service. Cho tiện demo thôi chứ khi làm thật ta nên tách ra cho dễ quản lý nhé các bạn
Sau đó ta apply
deploymet nhé:
kubectl apply -f deployment.yml --kubeconfig=./kubernetes-config
Tiếp theo ta check xem pod chạy ok không nhé:
kubectl get po --kubeconfig=./kubernetes-config
-->>>
NAME READY STATUS RESTARTS AGE
backend-785774cdcc-7pzb2 1/1 Running 0 1m47s
db-cd7458d4b-j86tl 1/1 Running 0 1m47s
frontend-7c8d646c5d-t7fp6 1/1 Running 0 1m47s
Check logs backend tí xem nó thế nào nào (thay tên pod của các bạn vào cho đúng nha):
kubectl logs backend-785774cdcc-7pzb2 --kubeconfig=./kubernetes-config
Thấy như sau là oke rồi 😎
chú ý rằng đoạn đầu backend start thì nó connect ngay đến DB, nhưng DB có thể mất chút thời gian để up, nên lần connect đầu backend có thể failed, nó sẽ tự restart và connect lại nhé
Ở file deployment.yml
, ta đang để service của frontend
là LoadBalancer
nên ta sẽ có thể truy cập trực tiếp từ tình duyệt để test thông qua IP của LB nha
Ta check xem IP của LB là gì trước nha:
kubectl get svc --kubeconfig=./kubernetes-config
--->>
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
backend ClusterIP 10.245.32.202 <none> 80/TCP 9m33s
db ClusterIP 10.245.49.191 <none> 80/TCP 9m33s
frontend LoadBalancer 10.245.190.193 <pending> 80:31420/TCP 9m33s
Như trên EXTERNAL-IP
của frontend
service vẫn là <pending>
tức là nó đang được tạo trên cloud, ta chờ chút nhé
Chờ tẹo get service lại ta sẽ thấy như sau:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
backend ClusterIP 10.245.32.202 <none> 80/TCP 10m
db ClusterIP 10.245.49.191 <none> 80/TCP 10m
frontend LoadBalancer 10.245.190.193 139.59.222.113 80:31420/TCP 10m
Ở trên địa chỉ service của mình là 139.59.222.113:80
, ta mở ở trình duyệt nhé:
Ta sẽ thấy UI đã lên, nhưng vẫn đang quay quay vì không gọi được tới backend, check console thì thấy là request tới /api
đang failed. Vì ta chưa có cấu hình gì để route request /api
vào backend, các bạn cứ bình tĩnh nha
Cấu hình Ingress
Quay lại tấm hình mô tả mình đã nói ở trên về flow request tới app của chúng ta:
Giờ ta sẽ cần tạo 1 ingress để điều phối tất cả request có path là /api
vào backend, /
vào frontend
Các bạn tạo cho mình file ingress.yml
nhé (sửa tên domain cho đúng với của các bạn nhé):
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: todo
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
# ingressClassName: nginx # Nếu bạn không muốn dùng annotations
rules:
- host: 75b79a.learnk8s.jamesisme.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend
port:
name: svc-http
- path: /api
pathType: Prefix
backend:
service:
name: backend
port:
name: svc-http
Ở trên các bạn thấy rằng:
- ta đang tạo resource với
kind: Ingress
- ta
annotate
resource này vớikubernetes.io/ingress.class: "nginx"
ý bảo là dùng nginx ingress nhé - bên dưới là ta định nghĩa các
rules
cho ingress này,rules
là 1 Array, ở đây array chỉ có 1 item - item này ta khai báo host là
75b79a.learnk8s.jamesisme.com
chính là cái domain mình nói ở phần lấy Session ý nhé, các bạn sửa tên domain cho đúng với của các bạn nha - và bên dưới ta có cấu hình
http
gồm 2 paths,/
-> frontend service, portsvc-http
của service đó. Tương tự/api
cho backend
Tiếp theo ta apply ingress nhé:
kubectl apply -f ingress.yml --kubeconfig=./kubernetes-config
Sau đó ta get ingress xem thế nào nha:
kubectl get ing --kubeconfig=./kubernetes-config
--->>
NAME CLASS HOSTS ADDRESS PORTS AGE
todo <none> 75b79a.learnk8s.jamesisme.com k8s.jamesisme.com 80 12m
Ở trên các bạn thấy rằng ingress của ta đã được tạo thành công, ADDRESS trỏ về domain k8s.jamesisme.com
, domain này trỏ về IP của Ingress Nginx Controller.
Thực tế với các cloud khác như AWS hay GCP thì sẽ hơi khác chút là nó sẽ show luôn IP của Nginx Ingress Controller ở đây, nhưng vì trên Digital Ocean nó hơi dị một chút 😂. Bạn nào tò mò có thể xem thêm ở đây
cái ADDRESS lúc mới tạo có thể chưa lên, các bạn chờ tí nhé
Giờ là ta có thể truy cập được từ tình duyệt với domain 75b79a.learnk8s.jamesisme.com
rồi đó:
Ủa nhưng mà bị sao vậy nhỉ???? 🙄 Mở console trình duyệt thì thấy báo 500 (Internal Server Error)
Oke thử check logs backend coi nào (thay tên backend của các bạn vào nha):
kubectl logs backend-785774cdcc-jnm8z --kubeconfig=./kubernetes-config
Úi quên chưa tạo bảng trong database 😁😁
Ta exec vào container và chạy migrate nhé:
kubectl exec -it backend-785774cdcc-jnm8z --kubeconfig=./kubernetes-config -- sh
yarn prisma migrate deploy
Sau đó ta quay trở lại trình duyệt F5 và có thể làm các thao tác CRUD rồi 😎
Pòm pòm chíu chíu lên rồi 😎😎😎🥳🥳🥳. Các bạn thử tạo vài cái todo, update delete các thứ coi sao nha
Chú ý rằng nếu các bạn bị lỗi HTTPS như bên dưới, thì khả năng là trình duyệt của các bạn đang tự redirect HTTP -> HTTPS, trường hợp này các bạn mở tab ẩn danh, trực tiếp gõ vào http://75b79a.learnk8s.jamesisme.com
là được nhé:
Vì giờ traffic đi vào sẽ tới domain và qua Nginx Ingress Controller, nên ta không cần expose frontend
service với type=LoadBalancer
nữa, ta đổi nó thành ClusterIP
để bảo mật hơn nhé (và cũng tiết kiệm hơn nữa vì cloud provider sẽ charge thêm phí với LB)
Ở file deployment.yml
ta sửa lại cấu hình service của frontend
nhé:
apiVersion: v1
kind: Service
metadata:
name: frontend
spec:
type: ClusterIP # <<-- sửa thành ClusterIP
ports:
- name: svc-http
protocol: TCP
port: 80
targetPort: pod-http
selector:
app: frontend
Sau đó ta apply lại:
kubectl apply -f deployment.yml --kubeconfig=./kubernetes-config
Âu cây vậy là bước đầu tiên đã xong rồi đó. Tiếp theo ta cùng xem lấy HTTPS cho domain của chúng ta như thế nào nhé
Tự động lấy HTTPS với cert-manager
Cài Cert-manager
Nhớ lại khi ta deploy app trên VPS, thường ta sẽ cần dùng tới certbot
sau đó chạy command sau để lấy HTTPS:
certbot --nginx -d example.com
Giờ trên K8S không có certbot thì ta lại có cert-manager để giúp ta làm điều đó.
Về cơ bản cert-manager sẽ tạo TLS cert cho các workload (resource) ta tạo trên K8S cluster, và tự renew cert trước khi mà nó hết hạn. Cert-manager thì có thể giúp chúng ta lấy HTTPS từ nhiều bên khác nhau: Let's Encrypt, HashiCorp Vault, Venafi and private PKI. Ở bài này ta sẽ dùng cái phổ biến nhất là Let's Encrypt nhé (giống certbot)
Và với certmanager thì cả cluster ta cũng thường chỉ cần 1 cert-manager là đủ, trừ khi ta có những yêu cầu cụ thể hơn. Do vậy ở trên cluster của mình thì mình cũng đã cài sẵn cho các bạn rồi và các bạn không cần làm gì nữa. Các cài thì cũng rất đơn giản, mình chỉ apply file manifest của cert-manager thôi
Mình không có làm gì đặc biệt, "giấu bài" đâu , nếu các bạn có cluster của riêng các bạn thì các bạn cũng làm 1 bước cài đặt như vậy thôi
Lấy HTTPS
Trước khi ta lấy HTTPS thì ta cần tạo manifest để cấu hình Issuer
, mục đích là để cert-manager hiểu cần phải lấy HTTPS như thế nào (Vì như bên trên mình nói cert-manager có thể lấy cert từ nhiều bên khác nhau, mỗi bên lại có cấu hình khác nhau)
Các bạn tạo cho mình file issuer.yml
nhé:
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: letsencrypt-prod
spec:
acme:
# The ACME server URL
server: https://acme-v02.api.letsencrypt.org/directory
# Email address used for ACME registration
email: test@gmail.com
# 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
Ở trên các bạn đổi email
cho phù hợp với của các bạn nhé.
Như bên trên các bạn thấy rằng ta tạo Issuer
với tên letsencrypt-prod
, issuer này sẽ được ăn vào namespace của các bạn, ngoài Issuer
thì ta cũng có ClusterIssuer
được dùng cho toàn bộ cluster, nhưng mình khuyên nên chỉ dùng Issuer
nếu có thể
Bên trên ta dùng server letsencrypt
và nói với cert-manager rằng ta đang dùng nginx ingress. Bên cạnh đó ta cũng để privateKeySecretRef
để lưu private key cho account ACME
1 Issuer có thể được dùng cho nhiều Ingress trên cùng namespace (đây cũng là cách mình hay dùng để đỡ phải quản lý nhiều issuer)
Bây giờ ta apply
để tạo Issuer nhé:
kubectl apply -f issuer.yml --kubeconfig=./kubernetes-config
Sau đó ta check xem trạng thái Issuer như thế nào nhé:
kubectl get issuer --kubeconfig=./kubernetes-config
--->>>
NAME READY AGE
letsencrypt-prod True 58s
Ở trên ta thấy READY=true rồi 👍️
Nếu các bạn muốn xem detail về issuer thì ta có thể describe
nhé:
kubectl describe issuer letsencrypt-prod --kubeconfig=./kubernetes-config
Giờ ta quay lại ingress.yml
và lấy HTTPS thôiiiii (nhớ thay domain của các bạn vào cho đúng):
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: todo
annotations:
kubernetes.io/ingress.class: "nginx"
cert-manager.io/issuer: "letsencrypt-prod"
spec:
tls:
- hosts:
- 75b79a.learnk8s.jamesisme.com
secretName: todo-tls
rules:
- host: 75b79a.learnk8s.jamesisme.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend
port:
name: svc-http
- path: /api
pathType: Prefix
backend:
service:
name: backend
port:
name: svc-http
Ở trên các bạn thấy rằng ta vừa thêm vào cert-manager.io/issuer: "letsencrypt-prod"
và tls
để chỉ định ta sẽ lấy HTTPS cho những host nào
Nếu ta muốn lấy HTTPS cho nhiều hơn 1 host thì ta làm như sau:
tls:
- hosts:
- jamesisme.com
- www.jamesisme.com
- www2.jamesisme.com
...
secretName: todo-tls
Ổn rồi đó giờ ta apply lại ingress nha:
kubectl apply -f ingress.yml --kubeconfig=./kubernetes-config
Sau đó ta check trạng thái ingress xem thế nào nhé:
kubectl get ing --kubeconfig=./kubernetes-config
---->>>
NAME CLASS HOSTS ADDRESS PORTS AGE
cm-acme-http-solver-54t4f <none> 75b79a.learnk8s.jamesisme.com 80 26s
todo <none> 75b79a.learnk8s.jamesisme.com k8s.jamesisme.com 80, 443 3h20m
Ta thấy rằng cert-manager đang tiến hành lấy HTTPS cho chúng ta, nếu trong lúc này ta quay lại trình duyệt và F5 sẽ thấy lỗi như sau:
Chờ thêm một chút và ta get ingress lại sẽ thấy như sau:
NAME CLASS HOSTS ADDRESS PORTS AGE
todo <none> 75b79a.learnk8s.jamesisme.com k8s.jamesisme.com 80, 443 29s
Giờ ta quay trở lại trình duyệt và F5:
Pòm, HTTPS đã lên rồi 💪💪💪💪💪🥳🥳🥳
Vọc vạch chút
Ta có thể check trạng thái certificate được tạo cho ingress của chúng ta như sau:
kubectl get cert --kubeconfig=./kubernetes-config
--->>>
NAME READY SECRET AGE
todo-tls True todo-tls 4m31s
Các bạn có thể decsribe
hoặc get -o yaml
để xem cụ thể bên trong cái cert kia như thế nào nhé
Nội dung thực tế của HTTPS cert của chúng ta thì được lưu ở secret như ta đã định nghĩa ở file ingress.yml
(todo-tls
), ta có thể xem như sau:
kubectl get secret todo-tls --kubeconfig=./kubernetes-config -o yaml
Giờ nếu ta thử update ingress để bỏ rule của route /api
đi:
- host: 75b79a.learnk8s.jamesisme.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend
port:
name: svc-http
# - path: /api
# pathType: Prefix
# backend:
# service:
# name: backend
# port:
# name: svc-http
Sau đó ta apply lại và quay lại trình duyệt thì ta thấy lại quay đều quay đều, tức là với mọi thay đổi của chúng ta thì nginx ingress controller đã ngay lập tức reload lại
Các câu hỏi liên quan
Ta có thể deploy nhiều Ingress Controller được không?
Hoàn toàn được nhé.
Nếu các bạn để ý, hiện tại cả cluster của chúng ta có 1 cái Controller, mọi request đi vào đều qua đó, nên nếu ví dụ khi ta check log thì ta sẽ thấy log toàn bộ các request vào cluster, giả sử ta có 10 apps traffic cao thì khi đó lượng log sẽ nhiều như thế nào
Hơn nữa trong trường hợp số request khủng quá thì còn có thể làm controller CPU/RAM tăng cao ảnh hưởng hiệu suất
Ta hoàn toàn có thể deploy mỗi namespace một cái ingress controller nhé, tuỳ vào nhu cầu
Search Google thấy có 2 Nginx Ingress Controller
Đúng vậy .
Hiện tại ta có 2 bản: của Nginx Inc. và của cộng đồng.
Mình thì thường dùng bản của cộng đồng phát triển, vì cũng chưa có nhu cầu gì khó, và tutorial toàn dùng cái đó
Muốn custom nginx thì như thế nào?
Ta có thể custom nginx cho Ingress của ta viết bằng Annotation, các bạn xem tất cả thuộc tính ở đây. Ta thêm nó vào annotations
ở ingress.yml
rồi apply lại là được
Kết bài
Phùuuuu.... Bài nào trong series viết xong cũng vỡ mặt thớt dù đã cố tinh gọn rồi 😂
Hi vọng qua bài này các bạn đã biết cách setup Ingress để điều phối traffic và lấy HTTPS cho app chạy Kubernetes.
Chúc các bạn ngủ ngon, hẹn gặp lại ở bài sau 😇
All rights reserved