Certified Kubernetes Administrator (CKA) with Practice Tests - Phần 4: Application Lifecycle Management
Rolling Updates and Rollbacks
Trước khi tìm hiểu cách nâng cấp ứng dụng của chúng ta, hãy thử hiểu về rollout (quy trình triển khai) và versioning trong một triển khai (deployment).
Khi tạo một deployment đầu tiên,, nó sẽ kích hoạt một lần triển khai mới (rollout). Mỗi lần kích hoạt rollout nó sẽ tạo ra một deployment mới ta gọi là Revision 1.
Trong tương lai khi ứng dụng được nâng cấp, tức là phiên bản của container được cập nhật mới, một đợi triển khai mới (rollout) sẽ được kích hoạt và tạo ra một deployment mới gọi là Revision 2.
Điều này giúp chúng ta theo dõi những thay đổi được thực hiện trong triển khai và cho phép quay lại phiên bản cũ (rollback), sang phiên bản triển khai trước đó nếu cần thiết.
Bạn có thể xem trạng thái triển khai(rollout) bằng lệnh:
$ kubectl rollout status deployment/myapp-deployment
Để xem các bản sửa đổi (revision) và lịch sử triển khai, chạy lệnh:
$ kubectl rollout history deployment/myapp-deployment
REVISION CHANGE-CAUSE
1 none
2 kubectl apply --filename=deployment-definition.yml --record=true
Có hai loại chiến lược triển khai:
Ví dụ: Bạn có 5 replica của một ứng dụng đang được triển khai.
Một cách để nâng cấp chúng lên phiên bản mới hơn là phá hủy tất cả và sau đó tạo ra phiên bản mới hơn.
Nghĩa là đầu tiên phá hủy cả 5 phiên bản đang chạy và sau đó triên khai 5 phiên bản mới. Trong khoảng thời gian sau khi phiên bản cũ bị phá hủy và trước khi phiên bản mới được tạo thì ứng dụng không hoạt động và người dùng không thể truy cập được, chiến lược này gọi là Recreate.
Chiến lược thứ 2 là không phá hủy tất cả cùng 1 lúc, thay vào đó chúng gỡ phiên bản cũ xuống và đưa từng phiên bản mới hơn vào. Bằng cách này ứng dụng sẽ không bao giờ ngừng hoạt động và việc nâng cấp diễn ra liền mạch, chiến lược này được gọi là Rolling Update.
Mặc định nếu không chỉ định chiến lược nào thì trong quá trình triển khai (deployment) nó sẽ chọn Rolling Update.
Khi một deployment mới được tạo, chẳng hạn để triển khai 5 replica, nó tự động tạo ra một replicaset, bộ này sẽ tạo số lượng pod cần thiết để đáp ứng số lượng bản replica.
Khi bạn nâng cấp ứng dụng, như đã thấy trước đó, đối tượng triển khai của Kubernetes tạo ra một replicaset mới và bắt đầu triển khai các container ở đó, đồng thời thu hồi các pod trong replicaset cũ theo chiến lược Rolling Update.
Điều này có thể nhìn thấy được khi bạn liệt kê Replicaset bằng lệnh:
$ kubectl get replicasets
NAME DESIRED CURRENT READY AGE
myapp-deployment-67c749c58c 0 0 0 22m
myapp-deployment-7d57dbdb8d 5 5 5 12m
Ở đây, chúng ta thấy replicaset cũ không có pod nào và replicaset mới có 5 pod.
Khi bạn nâng cấp ứng dụng của mình, bạn nhận ra có điều gì đó không ổn với phiên bản mới mà bạn đã sử dụng để nâng cấp. Vì vậy bạn muốn khôi phục bản cập nhật của mình về bản trước đó.
Kubernetes deployments cho phép bạn quay lại (rollback) phiên bản trước đó. Để hoàn tác một thay đổi, chạy lệnh:
$ kubectl rollout undo deployment/myapp-deployment
Sau đó, deployment sẽ phá hủy các pod trong replicaset mới và chạy các pod cũ lên trong replicaset cũ, và ứng dụng của bạn sẽ trở lại trạng thái cũ.
$ kubectl get replicasets
NAME DESIRED CURRENT READY AGE
myapp-deployment-67c749c58c 5 5 5 22m
myapp-deployment-7d57dbdb8d 0 0 0 12m
Configuring ConfigMaps in Applications
Khi bạn có nhiều pod sẽ trở nên khó quản lý dữ liệu environment được lưu trữ trong các file định nghĩa pod.
apiVersion: v1
kind: Pod
metadata:
name: simple-webapp-color
spec:
containers:
- name: simple-webapp-color
image: simpl-webapp-color
env:
- name: APP_COLOR
value: blue
- name: APP_MODE
value: prod
Có thể lấy các thông tin này ra khỏi file pod và quản lý nó một cách tập trung bằng cách sử dụng ConfigMaps. ConfigMaps được sử dụng để truyền dữ liệu config ở dạng cặp key:value trong kubernetes.
apiVersion: v1
kind: Pod
metadata:
name: simple-webapp-color
spec:
containers:
- name: simple-webapp-color
image: simpl-webapp-color
envFrom:
- configMapRef:
name: app-color
Khi một pod được tạo, hãy đưa configmap vào pod vì vậy các cặp key:value có sẵn như các biến môi trường (environment) cho ứng dựng được lưu trữ bên trong container.
Có hai giai đoạn liên quan đến việc cấu hình configMaps:
Tạo configMap
Sử dụng chúng trong pod
Giống như mọi đối tượng trong Kubernetes khác, có hai cách để để tạo một configMap là Imperative và Declarative.
Imperative:
$ kubectl create configmap <config-name> --from-literal=<key>=<value>
kubectl create configmap app-config --from-literal=APP_COLOR=blue \
--from-literal=APP_MODE=prod
$ kubectl create configmap <config-name> --from-file=<path-to-file>
kubectl create configmap app-config --from-file=app_config.properties
Declarative:
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
APP_COLOR: blue
APP_MODE: prod
Để xem danh sách configMaps, chạy lệnh:
$ kubectl get configmaps
NAME DATA AGE
app-config 2 3s
Các cấu hình nó vào trong pod, để thêm một biến môi trường thì thêm thuộc tính envFrom vào container. Nó là một list, vì vậy có thể chuyển bao nhiêu biến môi trường theo yêu cầu, mỗi mục tương ứng với một configMap chỉ định tên của configmap đã tạo trước đó.
apiVersion: v1
kind: Pod
metadata:
name: simple-webapp-color
spec:
containers:
- name: simple-webapp-color
image: simpl-webapp-color
envFrom:
- configMapRef:
name: app-config
Các cách để đưa dữ liệu từ configmap vào pod:
ENV:
envFrom:
- configMapRef:
name: app-config
SINGLE ENV:
env:
- name: APP_COLOR
valueFrom:
configMapKeyRef:
name: app-config
key: APP_COLOR
VOLUME:
volumes:
- name: app-config-volume
configMap:
name: app-config
Configure Secrets in Applications
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
DB_Host: mysql
DB_User: root
DB_Password: paswrd
Configmap lưu trữ dữ liệu ở định dạng plain text vì vậy có thể chuyển DB_Host & DB_User vào configmap, nó chắc chắn không phải là nới thích hợp để lưu trữ mật khẩu.
Đó là lúc Secrets xuất hiện, nó được sử dụng để lưu trữ thông tin nhảy cảm như mật khẩu.
Có hai cách để tạo Secrets:
Imperative:
$ kubectl create secret generic <secret-name> --from-literal=<key>=<value>
$ kubectl create secret generic <secret-name> --from-file=<path-to-file>
Declarative:
apiVersion: v1
kind: Secret
metadata:
name: app-secret
data:
DB_Host: mysql
DB_User: root
DB_Password: paswrd
Ở đây chúng ta đang khai báo dữ liệu ở dạng plain text, điều này không an toàn. Vì vậy khai khai báo secret ở dạng Declarative thì bạn phải chỉ định các giá trị bí mật ở định dạng được mã hóa. Dữ liệu ở dạng được mã hóa như thế này:
apiVersion: v1
kind: Secret
metadata:
name: app-secret
data:
DB_Host: bX1zcWw=
DB_User: cm9vdA==
DB_Password: cGFzd3Jk
Trên Linux, sử dụng lệnh:
$ echo -n "paswrd" | base64
cGFzd3Jk
$ echo -n "cGFzd3Jk" | base64 --decode
paswrd
Để xem secrets, hãy chạy lệnh:
$ kubetcl get secrets
NAME TYPE DATA AGE
app-secret Opaque 3 10m
Ở đây chúng ta có một file pod đơn giản sử dụng Secrets giống với ConfigMaps:
apiVersion: v1
kind: Pod
metadata:
name: simple-webapp-color
spec:
containers:
- name: simple-webapp-color
image: simpl-webapp-color
envFrom:
- secretRef:
name: app-secret
InitContainers
Nếu bạn chỉ định nhiều init container cho một Pod, kubelet sẽ chạy từng initContainer
theo trình tự. Mỗi initContainer
phải thành công trước khi initContainer
tiếp theo có thể chạy. Khi tất cả các initContainer
đã chạy đến khi hoàn tất, kubelet sẽ khởi tạo các ứng dụng container cho Pod và chạy chúng như bình thường.
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app.kubernetes.io/name: MyApp
spec:
containers:
- name: myapp-container
image: busybox:1.28
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
initContainers:
- name: init-myservice
image: busybox:1.28
command: ['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"]
- name: init-mydb
image: busybox:1.28
command: ['sh', '-c', "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done"]
Subscribe to my newsletter
Read articles from Phan Văn Hoàng directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by