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.

💡
Sự khác biệt giữa RecreateRolling Update là gì?

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:

  1. Tạo configMap

  2. 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 configMapImperativeDeclarative.

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
💡
Nhưng làm cách nào để chuyển từ plain text sang định dạng được mã hóa?

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"]
0
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

Phan Văn Hoàng
Phan Văn Hoàng