Serial blog Nhập môn Kubernetes
DaemonSet
DaemonSet có thể coi là một bản sao đặc biệt của ReplicaSet mà mình đã giới thiệu phần trước. ReplicaSet sẽ bố trí tổng số XXX Pod trên các Node trong Kubernetes phù hợp với tình trạng tài nguyên của các Node đó như thế nào. Chính vì vậy không hẳn là số lượng Pod được phân bổ vào các Node là bằng nhau, và cũng không không hẳn là phân bố cho tất cả các Node.
DaemonSet là loại resource phân bố Pod một cách tuần tự từng Pod một trên tất cả các Node. Chính vì vậy mà chúng ta không thể setting replica, không thể phân bổ từng 2 Pod một vào 1 Node được.
Nguồn: https://hackernoon.com/kubernetes-101-daemonsets-5-c5bbfcbb1579
Một trường hợp sử dụng DaemonSet như: khi chúng ta cần một chương trình nào đó nhất định phải chạy trên tất cả các Node
- Fluentd: Collect log xuất ra từ các Pod
- Datadog: Monitoring trạng thái hoạt động của các Node hay tình trạng sử dụng tài nguyên của các Pods.
Dưới đây là một user-case áp dụng DaemonSet
Nguồn: https://topdev.vn/blog/trien-khai-bo-log-tap-trung-centralized-logging-voi-docker-va-kubernettes-cho-server-su-dung-elk-stack/
Create DaemonSet
Chúng ta sẽ tạo một DaemonSet đơn giản, đầu tiên chúng ta cũng chuẩn bị file ds_sample.yml có nội dung dưới đây. Chúng ta sử dụng lại các pod đơn giản đã tạo ở phần trước. Khác với ReplicaSet, số lượng replica không cần setting.
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: sample-ds
spec:
selector:
matchLabels:
app: sample-app
template:
metadata:
labels:
app: sample-app
spec:
containers:
- name: nginx-container
image: nginx:1.12
ports:
- containerPort: 80
Create DaemonSet
$ kubectl apply -f ./ds_sample.yml
daemonset.apps/sample-ds created
Confirm DaemonSet đã được tạo OK chưa, có phải một Pod được phân bổ vào mỗi Node không.
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
sample-ds-6bxrx 1/1 Running 0 5m 10.42.2.23 Node2
sample-ds-8gggj 1/1 Running 0 5m 10.42.1.15 Node1
Ở đây mình đang chạy ở môi trường Kubernetes được thiết lập bằng Rancher 2.0 như đã trình bày ở phần 3, trong đó 2 Nodes.
StatefulSet
StatefulSet là resource cũng có thể nói là bản sao đặc biệt của ReplicaSet. Giống như tên gọi của nó, nó là loại resource để đối ứng trang thái Workload như là Database.
Khác với ReplicaSet ở những điểm sau:
- Tên các pod được tạo ra được đánh index bằng số.
- sample-statefulset-1, sample-statefulset-2, …… sample-statefulset-N
- Có cơ chế để cố định hoá
- Trường hợp đang sử dụng PersistentVolume thì nó sẽ Re create trên cùng một ổ đĩa.
- Tên Pod không thay đổi
Create StatefulSet
Chúng ta sẽ đi tạo một StatefulSet đơn giản. Đầu tiên chúng ta cũng chuẩn bị file statefulset_sample.yml có nội dung như dưới đây. Mình cũng sử dụng lại các Pod đã đã được tạo từ lần trước. So sánh với định nghĩa của ReplicaSet, chúng ta có thể setting thông số cho spec.volumeClaimTemplates. VolumeClaimTemplates sẽ cung cấp bộ nhớ ổn định bằng PersistentVolumes được cung cấp bởi PersistentVolume Provisioner.
Chi tiết tham khảo:
https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: sample-app
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: sample-app
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: sample-statefulset
spec:
replicas: 3 # by default is 1
selector:
matchLabels:
app: sample-app # has to match .spec.template.metadata.labels
serviceName: nginx
template:
metadata:
labels:
app: sample-app # has to match .spec.selector.matchLabels
spec:
containers:
- name: nginx-container
image: nginx:1.12
ports:
- containerPort: 80
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
Create StatefulSet
$ kubectl apply -f ./statefulset_sample.yml
statefulset "sample-statefulset" created
Thử kiểm tra xem. Các thông tin hiểu thị cũng giống như ReplicaSet
$ kubectl get statefulset
NAME DESIRED CURRENT AGE
sample-statefulset 3 3 14h
Kiểm tra các Pod được tạo bởi StatefulSet thì thấy có gắn index theo thứ tự 1 2 3 ... Thêm nữa trường hợp ta thêm hay xoá Pod bằng số lượng replica thì khác với ReplicaSet và DaemonSet, nó sẽ create/delete từng Pod một từng Pod một, việc này tốn rất ít thời gian.
Để các bạn dễ hình dung về cơ chế scale out/in của StatefulSet, mình mô tả bằng hình dưới đây.
StatefulSet scaling
Giống như với ReplicaSets, chúng ta có thể sử dụng 「kubectl scale」hoặc là 「kubectl apply -f」để scale.
Kiểm tra lưu trữ data khu vực cố định
Bây giờ chúng ta sẽ test xem: chẳng hạn như kiểm tra xem một file đã tòn tại ở khu vực lưu trữ hay chưa, nếu chưa có thì tạo mới.
$ kubectl exec -it sample-statefulset-0 ls /usr/share/nginx/html/sample.html
ls: cannot access '/usr/share/nginx/html/sample.html': No such file or directory
command terminated with exit code 2
# create file sample.html
$ kubectl exec -it sample-statefulset-0 touch /usr/share/nginx/html/sample.html
# confirm
$ kubectl exec -it sample-statefulset-0 ls /usr/share/nginx/html/sample.html
/usr/share/nginx/html/sample.html
Chẳng hạn như trong trường hợp Pod sample-statefulset-0 bị xoá, hoặc là có một exception nào đó xảy ra bên trong container hay là container bị stop đi chăng nữa, thì sau khi phục hồi trở lại, file sample.html đã được tạo trước đó cũng không bị mất.
$ kubectl delete pod sample-statefulset-0
pod "sample-statefulset-0" deleted
#Stop container
$ kubectl exec -it sample-statefulset-0 bash
root@sample-statefulset-0:/# kill 0
# File đã tạo vẫn tồn lại
$ kubectl exec -it sample-statefulset-0 ls /usr/share/nginx/html/sample.html
/usr/share/nginx/html/sample.html
Sau khi confirm trạng thái của StatefuleSet sau khi phục hồi, mặc dù IP Address thay đổi, nhưng chúng ta có thể thấy là tên pod không thay đổi.
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
sample-statefulset-0 1/1 Running 0 3m 10.8.1.10 gke-cluster-1-default-pool-8c632f08-mrp2
sample-statefulset-1 1/1 Running 0 51m 10.8.2.7 gke-cluster-1-default-pool-8c632f08-sdxm
sample-statefulset-2 1/1 Running 0 50m 10.8.0.7 gke-cluster-1-default-pool-8c632f08-d036
StatefulSet Life cycle
Khác với ReplicaSet, các Pod được tạo bởi StatefulSet không phân bố đồng thời vào các Node, nó sẽ create từng Pod một, đến khi nào Pod đó ở trạng thái Ready thì Pod thứ 2 mới bắt đầu được create. Thêm nữa khi xoá Pod, nó sẽ xoá ở Pod có index lớn nhất (Pod được tạo sau cùng).
Job
Là resource sử dụng container thực hiện xử lý chỉ một lần. Cụ thể hơn, nó là resource thực hiện xử lý một cách song song, đảm bảo thực thi container với số lần được chỉ định.
Khác nhau giữa sử dụng Job và Pod
Điểm khác nhau lớn nhất giữa Job, Pod và ReplicaSet là: "Pod có phải được tạo ra dựa trên tiền đề là việc stop hay không". Pod và ReplicaSet về cơ bản thì Stopped = Unexpected error, nhưng với Job thì Stopped = Nomal Finish. Thêm nữa, Pod và ReplicaSet không hẳn là đếm số lượng nomal finish, Trường hợp những xử lý kiểu như batch, thì mình khuyến khích xử dụng Job.
Create Job
Chúng ta sẽ làm một ví dụ nhỏ về Job, đầu tiên cũng chuẩn bị file YAML như bên dưới. Lần này mình sẽ tạo 1 Job thực hiện câu lệnh là sleep 60 giây. CŨng giống như ReplicaSets, mình có thể chỉ định label, selector, tuy nhiên kubernetes có cơ chế sinh ra một cách tự động để tránh xunng đột uuid. Vì vậy mình không khuyến khích các bạn setting nó ở đây.
#job_sample.yml
apiVersion: batch/v1
kind: Job
metadata:
name: sample-job
spec:
completions: 1
parallelism: 1
backoffLimit: 10
template:
spec:
containers:
- name: sleep-container
image: centos:latest
command: ["sleep"]
args: ["60"]
restartPolicy: Never
Create Job
$ kubectl apply -f job_sample.yml
job.batch/sample-job created
Confirm xem Job đã được khởi tạo chưa, khác với ReplicaSet vv, không hiển thị số lượng cotainer READY mà hiển thị số lượng nomal finish.
$ kubectl get jobs
NAME DESIRED SUCCESSFUL AGE
sample-job 1 1 6m
[operator_user@Kube-Rancher ~]$
[operator_user@Kube-Rancher ~]$ kubectl get pods
NAME READY STATUS RESTARTS AGE
sample-job-m4mjx 1/1 Running 0 8s
Khác nhau của hành vi với restartPolicy
Chúng ta có thể chỉ định cho tham số spec.template.spec.restartPolicy là OnFailure hay Never. Trường hợp là Never thì khi Pod gặp vất đề, sẽ tạo ra Pod mới thay thế. Trường hợp chỉ định là OnFailure, thì tiếp tục sử dụng Pod hiện tại chạy Job một lần nữa.
Thực thi kiểu hàng đợi và song song
Ở ví dụ phía trên, có 2 thông số là completions - số lần thực thi và parallelism - số lượng thực thi song song default là 1. Lần này ta thử thay đổi 2 tham số này như file bên dưới. Tham số backoffLimit là số lần cho phép thất bại.
apiVersion: batch/v1
kind: Job
metadata:
name: sample-paralleljob
spec:
completions: 10
parallelism: 2
backoffLimit: 10
template:
metadata:
name: sleep-job
spec:
containers:
- name: sleep-container
image: centos:latest
command: ["sleep"]
args: ["30"]
restartPolicy: Never
Kiểm tra hoạt động.
$ kubectl get jobs
NAME DESIRED SUCCESSFUL AGE
sample-paralleljob 10 4 1m
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
sample-paralleljob-58sgs 0/1 Completed 0 1m
sample-paralleljob-6j4fg 1/1 Running 0 22s
sample-paralleljob-d6jkm 0/1 Completed 0 1m
sample-paralleljob-pnppt 0/1 Completed 0 56s
sample-paralleljob-qvkd7 0/1 Completed 0 1m
sample-paralleljob-xjc57 1/1 Running 0 31s
completions, parallelism và backoffLimit là 3 parameter rất quan trọng, đối với Job workload chúng ta cần setting phù hợp.
Trường hợp ta muốn task chỉ thực hiện 1 lần duy nhất: Setting completions=1, parallelism=1, backoffLimit=1.
Bây giờ nếu chúng ta thay đổi các thông số completions=5, parallelism=3, backoffLimit=5. Đầu tiên sẽ tạo ra 3 Pod, sau khi 3 Pod chạy finish thì còn lại 2pods, 2Pod đó chạy hoàn thành nữa là OK.
Nếu chúng ta không chỉ định param completions thì sẽ sẽ chạy liên tục không dừng lại. Nếu param backoffLimit không được setting thì mặc định của nó là 6.
Chúng ta phải chú ý giá trị mặc định này.
CronJob
CronJob là loại resource giống với Job, cho đến kubernetes version 1.4 thì nó có tên gọi là ScheduledJob, bây giờ thì đổi thành CronJob. CronJob giống như một biến thể của Job, quan hệ giữa Job và CronJob cũng giống như Deployment và ReplicaSet. CronJob giống như Cron, thực hiện việc tạo các Job khi schedule.
Create CronJob
Tạo file cronjob_sample.yml có nội dung như bên dưới. Lần này mình tạo 1 CronJob có nhiệm vụ create Job (sleep 30s) sau mỗi 60s. Tham số cho spec.schedule giống như format của Cron vậy.
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: sample-cronjob
spec:
schedule: "*/1 * * * *"
concurrencyPolicy: Forbid
startingDeadlineSeconds: 30
successfulJobsHistoryLimit: 5
failedJobsHistoryLimit: 5
jobTemplate:
spec:
template:
spec:
containers:
- name: sleep-container
image: centos:latest
command: ["sleep"]
args: ["30"]
restartPolicy: Never
Create CronJob
$ kubectl apply -f cronjob_sample.yml
cronjob.batch/sample-cronjob created
Chúng ta cũng có thể sừ dụng 「kubectl run --schedule」 để tạo CronJob.
Lúc mới khởi tạo thì trạng thái sẽ là không tồn tại Job nào ACTIVE cả.
$ kubectl get cronjobs
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
sample-cronjob */1 * * * * False 0 <none> 10s
$ kubectl get job
No resources found.
Đến thời điểm như trong file setting, thì CronJob sẽ chạy
$ kubectl get cronjobs
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
sample-cronjob */1 * * * * False 1 14s 5m
$ kubectl get job
NAME DESIRED SUCCESSFUL AGE
sample-cronjob-1534666500 1 1 5m
sample-cronjob-1534666560 1 1 4m
sample-cronjob-1534666620 1 1 3m
sample-cronjob-1534666680 1 1 2m
sample-cronjob-1534666740 1 1 1m
Tạm dừng CronJob
Khi đã setting CronJob thì đến thời điểm nó sẽ chạy Job cho chúng ta. Trường hợp hệ thống đang mantain và chung ta muốn dừng CronJob thì cũng ta có thể thực hiện suspend (Tạm dừng). Trong CronJob, nhưng đối tượng được thiết lập spec.suspend là true sẽ nằm ngoài đối tượng được schedule. Chúng ta có thể chỉnh sửa file YAML và chạy lại lệnh 「kubectl apply」 cũng Ok, lần này mình sẽ sử dụng lệnh 「kubectl patch」 để thực hiện việc stop CronJob.
$ kubectl patch cronjob sample-cronjob -p '{"spec":{"suspend":true}}'
cronjob.batch/sample-cronjob patched
Thực hiện kubectl get cronjob để kiểm tra thì thấy giá trị SUSPEND đã hiển thị true, kể từ bây giờ thì Job sẽ không được tạo ra nữa. Nếu muốn thực hiện cronjob trở lại thì setting spec.suspend là false.
kubectl get cronjob
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
sample-cronjob */1 * * * * True 0 2m 3m
$ kubectl get job
NAME DESIRED SUCCESSFUL AGE
sample-cronjob-1534667460 1 1 4m
sample-cronjob-1534667520 1 1 3m
Kiểm soát liên quan đến thực thi đồng thời
CronJob có khả năng thiết lập policy liên quan đến thực thi đồng thời. Như mình đã trình bày, khi một job kết thúc thì Job mới được tạo ra. Tuy nhiên, ngay cả trong trường hợp Job cũ vẫn chưa kết thúc công việc thì vẫn có cơ chế để tạo Job mới chạy đồng thời.
Chúng ta có thể setting ở tham số spec.concurrencyPolicy
- Allow(default): Không hạn chế đối với việc thực thi đồng thời
- Forbid: Job trước đó thực hiện chưa xong thì không tạo Job mới.(không thực hiện đồng thời)
- Replace: Trong trường hợp Job cũ đang chạy, huỷ Job cũ và tạo Job mới
Ở CronJob, khi được setting thời gian chạy Job với Kubernetes Master, thì đến thời điểm đó, Job sẽ được khởi chạy. Chính vì vậy trong trường hợp Kubernetes Master bị down vv, chúng ta có thể chỉ định số giây cho phép có thể trễ bằng tham số spec.startingDeadlineSeconds . Ví dụ như chúng ta có thể setting Job chạy hàng giờ lúc 00 phút bằng cách cho phép nó chạy hàng giờ từ 00 phút đến 05 phút. Như vậy thì tham số chúng ta cần setting là spec.startingDeadlineSeconds: 300sec. Giá trị default của tham số này là cho dũ trễ bao lâu đi nữa nó vẫn khởi chạy Job cho chúng ta.
Ngoài ra ở CronJob có một parameter quan trọng là chỉ định số lượng Job luôn được duy trì, đó là spec.successfulJobsHistoryLimit và spec.failedJobsHistoryLimit:
- spec.successfulJobsHistoryLimit: Số lượng Job thành công được duy trì
- spec.failedJobsHistoryLimit: Số lượng Job thất bại duy trì.
Trong ví dụ phía trên thì mình có setting cho tham số spec.successfulJobsHistoryLimit: 5. Sau 6 phút kể từ khi chạy CronJob thì mình chạy lệnh kiểm tra kubectl get jobs, thì thu được kết quả là 5 Jobs gần nhất. Giá trị mặ định của tham số này là 3.
Phần tới mình sẽ giới thiệu về Discovery và Loab Balancing resource. Discovery&LB là loại resource cung cấp Endpoint cho phép truy cập từ bên ngoài đến các Workload resource đang được khởi chạy.