Sổ tay Kubernetes: làm việc với Ingress Controller (p2)
Loạt bài viết sổ tay Kubernetes:
- Sổ tay Kubernetes: Giới thiệu về Kubernetes.
- Sổ tay Kubernetes: Các khái niệm cơ bản trong Kubernetes.
- Sổ tay Kubernetes: Phương pháp triển khai bằng khai báo.
- Sổ tay Kubernetes: Triển khai ứng dụng đa container (p1).
- Sổ tay Kubernetes: Triển khai ứng dụng đa container (p2).
- Sổ tay Kubernetes: Triển khai ứng dụng đa container (p3).
- Sổ tay Kubernetes: làm việc với Ingress Controller (p1).
- Sổ tay Kubernetes: làm việc với Ingress Controller (p2) (bài viết này).
Ở phần 1, bạn đã tìm hiểu về Ingress Controller và cách sử dụng NGINX Ingress Controller để cấu hình định tuyến trong Kubernetes.
Trong phần 2 này, bạn sẽ tìm hiểu về Secret để lưu trữ các thông tin nhạy cảm, ConfigMap để lưu trữ thông tin cấu hình, phát hành cập nhật và xử lý sự cố trong Kubernetes.
Secret và ConfigMap trong Kubernetes
Cho đến lúc này trong các lần triển khai, bạn đã lưu trữ thông tin nhạy cảm như POSTGRES_PASSWORD
ở dạng văn bản thuần túy, đây không phải là một ý kiến hay.
Để lưu trữ các giá trị như vậy trong cụm của bạn, bạn có thể sử dụng một cách an toàn hơn nhiều là Secret
để lưu trữ mật khẩu, mã thông báo, v.v.
Bước tiếp theo có thể không hoạt động tương tự trong dòng lệnh Windows. Bạn có thể sử dụng git bash hoặc cmder cho tác vụ này.
Để lưu trữ thông tin trong Secret
trước tiên bạn phải chuyển dữ liệu của mình qua base64. Nếu mật khẩu văn bản thuần túy 63eaQB9wtLqmNBpg
thì thực thi lệnh sau để nhận phiên bản được mã hóa base64:
echo -n "63eaQB9wtLqmNBpg" | base64
# NjNlYVFCOXd0THFtTkJwZw==
Bước này không phải là tùy chọn, bạn phải chạy chuỗi văn bản thuần túy thông qua base64. Bây giờ, hãy tạo một tệp có tên postgres-secret.yaml
bên trong thư mục k8s
và đặt nội dung sau vào đó:
apiVersion: v1
kind: Secret
metadata:
name: postgres-secret
data:
password: NjNlYVFCOXd0THFtTkJwZw==
Các trường apiVersion
, kind
và metadata
khá dễ hiểu. Trường data
giữ bí mật thực tế.
Như bạn có thể thấy, tôi đã tạo một cặp khóa-giá trị trong đó khóa là password
và giá trị NjNlYVFCOXd0THFtTkJwZw==
. Bạn sẽ sử dụng giá trị metadata.name
để định danh Secret
trong các tệp cấu hình khác và khóa để truy cập giá trị mật khẩu.
Bây giờ để sử dụng bí mật này bên trong cấu hình cơ sở dữ liệu của bạn, hãy cập nhật tệp postgres-deployment.yaml
như sau:
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres-deployment
spec:
replicas: 1
selector:
matchLabels:
component: postgres
template:
metadata:
labels:
component: postgres
spec:
volumes:
- name: postgres-storage
persistentVolumeClaim:
claimName: database-persistent-volume-claim
containers:
- name: postgres
image: fhsinchy/notes-postgres
ports:
- containerPort: 5432
volumeMounts:
- name: postgres-storage
mountPath: /var/lib/postgresql/data
subPath: postgres
env:
# not putting the password directly anymore
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-secret
key: password
- name: POSTGRES_DB
value: notesdb
Như bạn có thể thấy, toàn bộ tệp đều giống nhau ngoại trừ trường spec.template.spec.continers.env
.
Trước đây, biến môi trường name
được sử dụng để lưu trữ giá trị mật khẩu ở dạng văn bản thuần túy. Nhưng bây giờ có một trường valueFrom.secretKeyRef
mới.
Trường name
ở đây đề cập đến tên của Secret
mà bạn đã tạo ở phần trước, và giá trị key
đề cập đến khóa từ cặp khóa-giá trị ở chỗ tập tin cấu hình Secret
. Giá trị được mã hóa sẽ được Kubernetes giải mã thành văn bản thuần túy trong nội bộ.
Ngoài cấu hình cơ sở dữ liệu, bạn cũng sẽ phải cập nhật tệp api-deployment.yaml
như sau:
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-deployment
spec:
replicas: 3
selector:
matchLabels:
component: api
template:
metadata:
labels:
component: api
spec:
containers:
- name: api
image: fhsinchy/notes-api
ports:
- containerPort: 3000
env:
- name: DB_CONNECTION
value: pg
- name: DB_HOST
value: postgres-cluster-ip-service
- name: DB_PORT
value: '5432'
- name: DB_USER
value: postgres
- name: DB_DATABASE
value: notesdb
# not putting the password directly anymore
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-secret
key: password
Bây giờ áp dụng tất cả các cấu hình mới này bằng cách thực hiện lệnh sau:
kubectl apply -f k8s
# service/api-cluster-ip-service created
# deployment.apps/api-deployment created
# service/client-cluster-ip-service created
# deployment.apps/client-deployment created
# persistentvolumeclaim/database-persistent-volume-claim created
# secret/postgres-secret created
# ingress.extensions/ingress-service created
# service/postgres-cluster-ip-service created
# deployment.apps/postgres-deployment created
Tùy thuộc vào trạng thái của cụm của bạn, bạn có thể thấy một tập hợp đầu ra khác nhau.
Trong trường hợp bạn đang gặp bất kỳ sự cố nào, hãy xóa tất cả tài nguyên Kubernetes và tạo lại chúng bằng cách áp dụng lại các cấu hình.
Sử dụng lệnh get
để kiểm tra và đảm bảo rằng tất cả các nhóm đều đang hoạt động.
Bây giờ để kiểm tra cấu hình mới, hãy truy cập ứng dụng ghi chú bằng lệnh minikube
IP và thử tạo ghi chú mới. Để lấy IP, bạn có thể thực hiện lệnh sau:
minikube ip
# 172.17.0.2
Bằng cách truy cập 127.17.0.2:80
, bạn sẽ truy cập trực tiếp vào ứng dụng ghi chú.

Có một cách khác để tạo secret mà không cần bất kỳ tệp cấu hình nào. Để tạo Secret
tương tự bằng cách sử dụng lệnh kubectl
, hãy thực hiện lệnh sau:
kubectl create secret generic postgres-secret --from-literal=password=63eaQB9wtLqmNBpg
# secret/postgres-secret created
Đây là một cách tiếp cận thuận tiện hơn vì bạn có thể bỏ qua toàn bộ bước mã hóa base64. Secret trong trường hợp này sẽ được mã hóa tự động.
ConfigMap
tương tự như Secret
nhưng được sử dụng với thông tin không nhạy cảm.
Để đặt tất cả các biến môi trường khác trong triển khai API bên trong một ConfigMap
, hãy tạo một tệp mới có tên api-config-map.yaml
bên trong thư mục k8s
và đưa nội dung sau vào đó:
apiVersion: v1
kind: ConfigMap
metadata:
name: api-config-map
data:
DB_CONNECTION: pg
DB_HOST: postgres-cluster-ip-service
DB_PORT: '5432'
DB_USER: postgres
DB_DATABASE: notesdb
Các trường apiVersion
, kind
và metadata
đã quá dễ hiểu. Trường data
có thể chứa các biến môi trường dưới dạng các cặp khóa-giá trị.
Không giống như Secret
, các khóa ở đây phải khớp với khóa chính xác mà API yêu cầu. Do đó, tôi đã sao chép các biến từ tệp api-deployment.yaml
và dán chúng vào đây với một chút sửa đổi trong cú pháp.
Để sử dụng cấu hình này trong triển khai API, hãy mở tệp api-deployment.yaml
và cập nhật nội dung của nó như sau:
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-deployment
spec:
replicas: 3
selector:
matchLabels:
component: api
template:
metadata:
labels:
component: api
spec:
containers:
- name: api
image: fhsinchy/notes-api
ports:
- containerPort: 3000
# not putting environment variables directly
envFrom:
- configMapRef:
name: api-config-map
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-secret
key: password
Toàn bộ tệp hầu như không thay đổi ngoại trừ trường spec.template.spec.containers.env
.
Tôi đã chuyển các biến môi trường sang ConfigMap
. Trường spec.template.spec.containers.envFrom
được sử dụng để lấy dữ liệu từ ConfigMap
. Trường configMapRef.name
ở đây chỉ ra ConfigMap
nơi mà các biến môi trường sẽ được kéo.
Bây giờ áp dụng tất cả các cấu hình mới này bằng cách thực hiện lệnh sau:
kubectl apply -f k8s
# service/api-cluster-ip-service created
# configmap/api-config-map created
# deployment.apps/api-deployment created
# service/client-cluster-ip-service created
# deployment.apps/client-deployment created
# persistentvolumeclaim/database-persistent-volume-claim created
# ingress.extensions/ingress-service configured
# service/postgres-cluster-ip-service created
# deployment.apps/postgres-deployment created
# secret/postgres-secret created
Tùy thuộc vào trạng thái của cụm của bạn, bạn có thể thấy một tập hợp đầu ra khác nhau.
Trong trường hợp bạn đang gặp bất kỳ sự cố nào, hãy xóa tất cả tài nguyên Kubernetes và tạo lại chúng bằng cách áp dụng lại các cấu hình.
Sau khi đảm bảo rằng các pod đã được thiết lập và đang chạy bằng lệnh get
, hãy truy cập ứng dụng ghi chú bằng minikube
IP và thử tạo ghi chú mới.
Để lấy IP, bạn có thể thực hiện lệnh sau:
minikube ip
# 172.17.0.2
Bằng cách truy cập 127.17.0.2:80
, bạn sẽ truy cập trực tiếp vào ứng dụng ghi chú.

Secret
và ConfigMap
có thêm một vài thủ thuật mà tôi sẽ không trình bày ở đây. Nhưng nếu bạn tò mò, bạn có thể xem các tài liệu chính thức.
Thực hiện phát hành cập nhật trong Kubernetes
Bây giờ bạn đã triển khai thành công một ứng dụng bao gồm nhiều container trên Kubernetes, đã đến lúc tìm hiểu về việc thực hiện cập nhật.
Có vẻ như Kubernetes kỳ diệu đối với bạn, việc cập nhật container lên phiên bản image mới hơn là một chút khó khăn. Có nhiều cách tiếp cận mà mọi người thường thực hiện để cập nhật container, nhưng tôi sẽ không đi hết tất cả chúng.
Thay vào đó, tôi sẽ chuyển ngay sang cách tiếp cận mà tôi chủ yếu thực hiện khi cập nhật container của mình. Nếu bạn mở tệp client-deployment.yaml
và nhìn vào trường spec.template.spec.containers
, bạn sẽ thấy một cái gì đó giống như sau:
containers:
- name: client
image: fhsinchy/notes-client
Như bạn có thể thấy, trong trường image
này, tôi chưa sử dụng bất kỳ image tag nào. Bây giờ nếu bạn nghĩ rằng việc thêm :latest
vào cuối tên image sẽ đảm bảo rằng việc triển khai luôn kéo image mới nhất có sẵn, bạn đã nhầm.
Cách tiếp cận mà tôi thường áp dụng là cách tiếp cận bắt buộc. Tôi đã đề cập trong phần trước rằng, trong một vài trường hợp, sử dụng cách tiếp cận mệnh lệnh thay vì cách tiếp cận khai báo là một ý tưởng hay. Việc tạo Secret
hoặc cập nhật container là một trường hợp như vậy.
Lệnh bạn có thể sử dụng để thực hiện cập nhật là lệnh set
và cú pháp chung như sau:
kubectl set image <resource type>/<resource name> <container name>=<image name with tag>
Loại tài nguyên là deployment
và tên tài nguyên client-deployment
. Tên container có thể được tìm thấy dưới trường containers
bên trong tệp client-deployment.yaml
, nó là client
trong trường hợp này.
Tôi đã tạo một phiên bản của image fhsinchy/notes-client
với thẻ edge
mà tôi sẽ sử dụng để cập nhật triển khai này.
Vì vậy, lệnh cuối cùng sẽ như sau:
kubectl set image deployment/client-deployment client=fhsinchy/notes-client:edge
# deployment.apps/client-deployment image updated
Quá trình cập nhật có thể mất một lúc vì Kubernetes sẽ tạo lại tất cả các pod. Bạn có thể chạy lệnh get
để biết liệu tất cả các pod đã hoạt động hay chưa và đang chạy lại.
Sau khi tất cả chúng đã được tạo lại, hãy truy cập ứng dụng ghi chú bằng minikube
IP và thử tạo ghi chú mới. Để lấy IP, bạn có thể thực hiện lệnh sau:
minikube ip
# 172.17.0.2
Bằng cách truy cập 127.17.0.2:80
, bạn sẽ truy cập trực tiếp vào ứng dụng ghi chú.

Bạn có thể cho rằng tôi đã không thực hiện bất kỳ thay đổi thực tế nào đối với mã ứng dụng, mọi thứ sẽ vẫn như cũ. Bạn có thể đảm bảo rằng các pod đang sử dụng image mới bằng lệnh describe
.
kubectl describe pod client-deployment-849bc58bcc-gz26b | grep 'Image'
# Image: fhsinchy/notes-client:edge
# Image ID: docker-pullable://fhsinchy/notes-client@sha256:58bce38c16376df0f6d1320554a56df772e30a568d251b007506fd3b5eb8d7c2
Lệnh grep
có sẵn trên máy Mac và Linux. Nếu bạn đang sử dụng Windows, hãy sử dụng git bash thay vì dòng lệnh windows.
Mặc dù quy trình cập nhật bắt buộc hơi tẻ nhạt, nhưng nó có thể được thực hiện dễ dàng hơn nhiều bằng cách sử dụng quy trình làm việc CI/CD tốt.
Kết hợp các cấu hình
Như bạn đã thấy, số lượng tệp cấu hình trong dự án này là khá lớn mặc dù chỉ có ba container trong đó.
Bạn thực sự có thể kết hợp các tệp cấu hình như sau:
apiVersion: apps/v1
kind: Deployment
metadata:
name: client-deployment
spec:
replicas: 3
selector:
matchLabels:
component: client
template:
metadata:
labels:
component: client
spec:
containers:
- name: client
image: fhsinchy/notes-client
ports:
- containerPort: 8080
env:
- name: VUE_APP_API_URL
value: /api
---
apiVersion: v1
kind: Service
metadata:
name: client-cluster-ip-service
spec:
type: ClusterIP
selector:
component: client
ports:
- port: 8080
targetPort: 8080
Như bạn có thể thấy, tôi đã kết hợp nội dung của tệp client-deployment.yaml
và tệp client-cluster-ip-service.yaml
bằng dấu phân cách (---
). Mặc dù có thể và có thể hữu ích trong các dự án có số lượng container rất cao, tôi khuyên bạn nên giữ chúng riêng biệt, sạch sẽ và ngắn gọn.
Xử lý sự cố
Trong phần này, tôi sẽ liệt kê một số vấn đề phổ biến mà bạn có thể gặp phải trong thời gian làm việc với Kubernetes.
- Nếu bạn đang sử dụng Windows hoặc Mac và sử dụng trình điều khiển Docker cho
minikube
, pluginIngress
sẽ không hoạt động. - Nếu bạn có Laravel Valet đang chạy trên Mac và đang sử dụng trình điều khiển HyperKit
minikube
, nó sẽ không kết nối được với Internet. Tắt dịch vụdnsmasq
sẽ giải quyết được sự cố. - Nếu bạn có PC Ryzen (của tôi là R5 1600) và đang chạy Windows 10, trình điều khiển VirtualBox có thể không khởi động được do thiếu hỗ trợ ảo hóa lồng nhau. Bạn sẽ phải sử dụng trình điều khiển Hyper-V trên Windows 10 (Pro, Enterprise và Education). Đối với người dùng phiên bản Home, thật đáng buồn là không có tùy chọn an toàn nào trên phần cứng đó.
- Nếu bạn đang chạy Windows 10 (Pro, Enterprise và Education) với trình điều khiển Hyper-V cho
minikube
, máy ảo có thể không khởi động được với thông báo về việc không đủ bộ nhớ. Đừng hoảng sợ và thực hiện lệnhminikube start
một lần nữa để khởi động máy ảo đúng cách. - Nếu bạn thấy một số lệnh được thực thi trong bài viết này bị thiếu hoặc hoạt động sai trong dòng lệnh Windows, hãy sử dụng git bash hoặc cmder để thay thế.
Tôi khuyên bạn nên cài đặt một bản phân phối Linux tốt trên hệ thống của bạn và sử dụng trình điều khiển Docker cho minikube
. Đây là cách thiết lập nhanh nhất và đáng tin cậy nhất.
Phần kết luận
Tôi xin cảm ơn từ tận đáy lòng vì thời gian bạn đã dành để đọc loạt bài viết này. Tôi hy vọng bạn đã tận hưởng thời gian của mình và đã học được tất cả những điều cần thiết về Kubernetes.