更新時(shí)間:2020-04-30 來(lái)源:黑馬程序員 瀏覽量:
一、Pod控制器
Pod 的分類(lèi)
1、自主式 Pod
Pod 退出后不會(huì)被創(chuàng)建
2、控制器管理的 Pod
在控制器的生命周期里,始終要維持 Pod 的副本數(shù)目
3、控制器類(lèi)型
Replication Controller和ReplicaSetDeploymentDaemonSetStatefulSetJobCronJobHPA全稱(chēng)Horizontal Pod AutoscalerReplication Controller和ReplicaSetReplicaSet (RS)是下一代的 Replication Controller(RC),官方推薦使用ReplicaSet。
ReplicaSet 和 Replication Controller 的唯一區(qū)別是選擇器的支持,ReplicaSet 支持新的基于集合的選擇器需求。
ReplicaSet 確保任何時(shí)間都有指定數(shù)量的 Pod 副本在運(yùn)行。
雖然 ReplicaSets 可以獨(dú)立使用,但今天它主要被Deployments 用作協(xié)調(diào) Pod 創(chuàng)建、刪除和更新的機(jī)制。推薦了解黑馬程序員linux云計(jì)算+運(yùn)維開(kāi)發(fā)課程。
1)Deployment
Deployment 為 Pod 和 ReplicaSet 提供了一個(gè)申明式的定義方法。
.典型的應(yīng)用場(chǎng)景:
用來(lái)創(chuàng)建Pod和ReplicaSet滾動(dòng)更新和回滾擴(kuò)容和縮容暫停與恢復(fù)
2)DaemonSet
DaemonSet 確保全部(或者某些)節(jié)點(diǎn)上運(yùn)行一個(gè) Pod 的副本。當(dāng)有節(jié)點(diǎn)加入集群時(shí), 也會(huì)為他們新增一個(gè) Pod 。當(dāng)有節(jié)點(diǎn)從集群移除時(shí),這些 Pod 也會(huì)被回收。刪除 DaemonSet 將會(huì)刪除它創(chuàng)建的所有 Pod。
DaemonSet 的典型用法:
在每個(gè)節(jié)點(diǎn)上運(yùn)行集群存儲(chǔ) DaemonSet,例如 glusterd、ceph。在每個(gè)節(jié)點(diǎn)上運(yùn)行日志收集 DaemonSet,例如 fluentd、logstash。在每個(gè)節(jié)點(diǎn)上運(yùn)行監(jiān)控 DaemonSet,例如 Prometheus Node Exporter、zabbix agent等一個(gè)簡(jiǎn)單的用法是在所有的節(jié)點(diǎn)上都啟動(dòng)一個(gè) DaemonSet,將被作為每種類(lèi)型的 daemon 使用。
一個(gè)稍微復(fù)雜的用法是單獨(dú)對(duì)每種 daemon 類(lèi)型使用多個(gè) DaemonSet,但具有不同的標(biāo)志, 并且對(duì)不同硬件類(lèi)型具有不同的內(nèi)存、CPU 要求。
3)StatefulSet
StatefulSet 是用來(lái)管理有狀態(tài)應(yīng)用的工作負(fù)載 API 對(duì)象。實(shí)例之間有不對(duì)等關(guān)系,以及實(shí)例對(duì)外部數(shù)據(jù)有依賴(lài)關(guān)系的應(yīng)用,稱(chēng)為“有狀態(tài)應(yīng)用”
StatefulSet 用來(lái)管理 Deployment 和擴(kuò)展一組 Pod,并且能為這些 Pod 提供序號(hào)和唯一性保證。
StatefulSets 對(duì)于需要滿(mǎn)足以下一個(gè)或多個(gè)需求的應(yīng)用程序很有價(jià)值:
穩(wěn)定的、唯一的網(wǎng)絡(luò)標(biāo)識(shí)符。穩(wěn)定的、持久的存儲(chǔ)。有序的、優(yōu)雅的部署和縮放。有序的、自動(dòng)的滾動(dòng)更新。Job執(zhí)行批處理任務(wù),僅執(zhí)行一次任務(wù),保證任務(wù)的一個(gè)或多個(gè)Pod成功結(jié)束。
4)CronJob
Cron Job 創(chuàng)建基于時(shí)間調(diào)度的 Jobs。
一個(gè) CronJob 對(duì)象就像 crontab (cron table) 文件中的一行,它用 Cron 格式進(jìn)行編寫(xiě),并周期性地在給定的調(diào)度時(shí)間執(zhí)行 Job。
HPA根據(jù)資源利用率自動(dòng)調(diào)整service中Pod數(shù)量,實(shí)現(xiàn)Pod水平自動(dòng)縮放。
二、Pod控制器使用示例
ReplicaSet舉例
1、編輯以下yaml文件:
[root@server1 ~]# vim rs.yaml
[root@server1 ~]# cat rs.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: replicaset-example
spec:
replicas: 2 #啟動(dòng)pod的副本數(shù)
selector: #定義選擇器為標(biāo)簽選擇器。
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx #定義容器的標(biāo)簽
spec: #定義容器
containers:
- name: nginx
image: nginx
2、運(yùn)行
以上使用的控制器的RS,RS控制器通過(guò)pod的標(biāo)簽(matchLabels)來(lái)控制pod的數(shù)量,使用apply命令可以實(shí)現(xiàn)創(chuàng)建,更新pod,而create命令創(chuàng)建后若需要更新只能刪除之后再創(chuàng)建,因此建議使用apply:
[root@server1 ~]# kubectl apply -f rs.yaml
replicaset.apps/replicaset-example created
[root@server1 ~]# kubectl apply -f rs.yaml
replicaset.apps/replicaset-example unchanged
3、查看狀態(tài):
[root@server1 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
replicaset-example-p6sv6 1/1 Running 0 34s
replicaset-example-s5jps 1/1 Running 0 34s
[root@server1 ~]# kubectl get rs #獲取rs的信息
NAME DESIRED CURRENT READY AGE
replicaset-example 2 2 2 36s
[root@server1 ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
replicaset-example-p6sv6 1/1 Running 0 38s 10.244.1.14 server2 <none> <none>
replicaset-example-s5jps 1/1 Running 0 38s 10.244.2.21 server3 <none> <none>
可以看出一且正常,接下來(lái)進(jìn)行pod的拉伸與壓縮:
4、拉伸副本數(shù):
[root@server1 ~]# vim rs.yaml
[root@server1 ~]# cat rs.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: replicaset-example
spec:
replicas: 4 #拉伸為4個(gè)
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
[root@server1 ~]# kubectl apply -f rs.yaml
replicaset.apps/replicaset-example configured
5、查看pod數(shù)
[root@server1 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
replicaset-example-p6sv6 1/1 Running 0 97s
replicaset-example-s5jps 1/1 Running 0 97s
replicaset-example-wzclz 1/1 Running 0 21s
replicaset-example-zk4mb 1/1 Running 0 21s
已經(jīng)被拉伸成了4個(gè)。
6、縮減
[root@server1 ~]# vim rs.yaml
[root@server1 ~]# cat rs.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: replicaset-example
spec:
replicas: 2 #縮減為2個(gè)
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
[root@server1 ~]# kubectl apply -f rs.yaml
replicaset.apps/replicaset-example configured
[root@server1 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
replicaset-example-p6sv6 1/1 Running 0 2m6s
replicaset-example-s5jps 1/1 Running 0 2m6s
可以看出刪除的是剛剛創(chuàng)建的那兩個(gè)pod。
7、更改一個(gè)pod 的標(biāo)簽:
[root@server1 ~]# kubectl label pod replicaset-example-s5jps app=myapp --overwrite #將標(biāo)簽強(qiáng)制更改為myapp
pod/replicaset-example-s5jps labeled
[root@server1 ~]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
replicaset-example-p6sv6 1/1 Running 0 3m56s app=nginx
replicaset-example-s5jps 1/1 Running 0 3m56s app=myapp
replicaset-example-w98nk 1/1 Running 0 26s app=nginx
可以看出現(xiàn)在有3個(gè)pod,兩個(gè)標(biāo)簽為nginx一個(gè)為myapp,RS控制器的工作原理就是維持標(biāo)簽為nginx的pod個(gè)數(shù)有2個(gè),因此當(dāng)我們更改一個(gè)pod的標(biāo)簽后,RS又會(huì)給我們創(chuàng)建一個(gè)標(biāo)簽為nginx的pod,而當(dāng)我們將標(biāo)簽為myapp的pod刪除后RS控制器不會(huì)有操作:
[root@server1 ~]# kubectl delete pod replicaset-example-s5jps
pod "replicaset-example-s5jps" deleted
[root@server1 ~]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
replicaset-example-p6sv6 1/1 Running 0 5m8s app=nginx
replicaset-example-w98nk 1/1 Running 0 98s app=nginx
8、再更改驗(yàn)證:
[root@server1 ~]# kubectl label pod replicaset-example-p6sv6 app=myapp --overwrite #首先保證3個(gè)pod
pod/replicaset-example-p6sv6 labeled
[root@server1 ~]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
replicaset-example-p6sv6 1/1 Running 0 6m4s app=myapp
replicaset-example-w98nk 1/1 Running 0 2m34s app=nginx
replicaset-example-x2lq9 1/1 Running 0 26s app=nginx
[root@server1 ~]# kubectl label pod replicaset-example-p6sv6 app=nginx --overwrite
pod/replicaset-example-p6sv6 labeled
[root@server1 ~]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
replicaset-example-p6sv6 1/1 Running 0 6m23s app=nginx
replicaset-example-w98nk 1/1 Running 0 2m53s app=nginx
replicaset-example-x2lq9 0/1 Terminating 0 45s app=nginx
[root@server1 ~]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
replicaset-example-p6sv6 1/1 Running 0 6m25s app=nginx
replicaset-example-w98nk 1/1 Running 0 2m55s app=nginx
以上實(shí)驗(yàn)可以看出,當(dāng)集群里有3個(gè)標(biāo)簽是nginx的pod的時(shí)候,RS控制器又會(huì)幫我們將最后創(chuàng)建的pod刪除。
實(shí)驗(yàn)后刪除:
[root@server1 ~]# kubectl delete -f rs.yaml
replicaset.apps "replicaset-example" deleted
Deployment控制器示例
1、編輯yaml文件:
Deployment控制器示例 編輯yaml文件:
[root@server1 ~]# vim deployment.yaml
[root@server1 ~]# cat deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-nginx
labels:
app: nginx
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: ikubernetes/myapp:v1
ports:
- containerPort: 80
2、創(chuàng)建pod:
[root@server1 ~]# kubectl apply -f deployment.yaml
deployment.apps/deployment-nginx created
[root@server1 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
deployment-nginx-56d786cd98-kx5pw 1/1 Running 0 23s
deployment-nginx-56d786cd98-qgcjl 1/1 Running 0 23s
[root@server1 ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
deployment-nginx-56d786cd98 2 2 2 28s
[root@server1 ~]# kubectl get deployments.apps #查看deployments
NAME READY UP-TO-DATE AVAILABLE AGE
deployment-nginx 2/2 2 2 32s
以上運(yùn)行結(jié)果可以看出deployments底層也是由RS實(shí)現(xiàn)的,接下來(lái)
3、進(jìn)行拉伸:
[root@server1 ~]# vim deployment.yaml
[root@server1 ~]# cat deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-nginx
labels:
app: nginx
spec:
replicas: 4 #拉伸為4個(gè)
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: ikubernetes/myapp:v1
ports:
- containerPort: 80
[root@server1 ~]# kubectl apply -f deployment.yaml
deployment.apps/deployment-nginx configured
[root@server1 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
deployment-nginx-56d786cd98-942dh 1/1 Running 0 26s
deployment-nginx-56d786cd98-kx5pw 1/1 Running 0 108s
deployment-nginx-56d786cd98-qgcjl 1/1 Running 0 108s
deployment-nginx-56d786cd98-zb8s8 1/1 Running 0 26s
可以看出已經(jīng)拉伸為4個(gè)。接下來(lái)進(jìn)行
4、滾動(dòng)更新:
[root@server1 ~]# vim deployment.yaml
[root@server1 ~]# cat deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-nginx
labels:
app: nginx
spec:
replicas: 4
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: ikubernetes/myapp:v2 #更新到v2
ports:
- containerPort: 80
[root@server1 ~]# kubectl apply -f deployment.yaml
deployment.apps/deployment-nginx configured
[root@server1 ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
deployment-nginx-868855d887-2zh45 1/1 Running 0 2m39s 10.244.2.26 server3 <none> <none>
deployment-nginx-868855d887-87m22 1/1 Running 0 2m34s 10.244.1.20 server2 <none> <none>
deployment-nginx-868855d887-hb6mv 1/1 Running 0 2m39s 10.244.1.19 server2 <none> <none>
deployment-nginx-868855d887-v8ndt 1/1 Running 0 2m33s 10.244.2.27 server3 <none> <none>
[root@server1 ~]# curl 10.244.2.26
Hello MyApp | Version: v2 | Pod Name
可以看出更新時(shí)控制器新建一個(gè)rs,然后再新建4個(gè)pod,原來(lái)的rs依然存在,為了方便我們
5、進(jìn)行回滾:
[root@server1 ~]# vim deployment.yaml
[root@server1 ~]# cat deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-nginx
labels:
app: nginx
spec:
replicas: 4
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: ikubernetes/myapp:v1
ports:
- containerPort: 80
[root@server1 ~]# kubectl apply -f deployment.yaml
deployment.apps/deployment-nginx configured
[root@server1 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
deployment-nginx-56d786cd98-78m7z 0/1 ContainerCreating 0 4s
deployment-nginx-56d786cd98-8hnns 1/1 Running 0 9s
deployment-nginx-56d786cd98-lcvzw 1/1 Running 0 9s
deployment-nginx-56d786cd98-xkjhq 0/1 ContainerCreating 0 3s
deployment-nginx-868855d887-2zh45 1/1 Running 0 3m22s
deployment-nginx-868855d887-hb6mv 1/1 Terminating 0 3m22s
deployment-nginx-868855d887-v8ndt 1/1 Terminating 0 3m16s
[root@server1 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
deployment-nginx-56d786cd98-78m7z 1/1 Running 0 26s
deployment-nginx-56d786cd98-8hnns 1/1 Running 0 31s
deployment-nginx-56d786cd98-lcvzw 1/1 Running 0 31s
deployment-nginx-56d786cd98-xkjhq 1/1 Running 0 25s
可以看出原來(lái)v1版本的rs被重新啟用,再原來(lái)的rs下面新建4個(gè)pod。當(dāng)然我門(mén)也可以使用kubectl delete rs --all命令刪除不用的rs(注意:正在使用的rs不會(huì)刪除):
[root@server1 ~]# kubectl delete rs --all
replicaset.apps "deployment-nginx-56d786cd98" deleted
replicaset.apps "deployment-nginx-868855d887" deleted
[root@server1 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
deployment-nginx-56d786cd98-6r589 1/1 Running 0 21s
deployment-nginx-56d786cd98-hvz24 1/1 Running 0 21s
deployment-nginx-56d786cd98-k62lj 1/1 Running 0 21s
deployment-nginx-56d786cd98-ss97z 1/1 Running 0 21s
[root@server1 ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
deployment-nginx-56d786cd98 4 4 4 24s #正在使用的RS不會(huì)刪除
實(shí)驗(yàn)后刪除:
[root@server1 ~]# kubectl delete -f deployment.yaml
deployment.apps "deployment-nginx" deleted
DaemonSet舉例
1、編輯yaml
DaemonSet控制器保證每個(gè)節(jié)點(diǎn)上都運(yùn)行一個(gè)pod:
[root@server1 ~]# vim daemonset.yaml
[root@server1 ~]# cat daemonset.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: daemonset-example
labels:
app: zabbix-agent
spec:
selector:
matchLabels:
name: zabbix-agent
template:
metadata:
labels:
name: zabbix-agent
spec:
containers:
- name: zabbix-agent
image: zabbix/zabbix-agent
2、創(chuàng)建pod:
[root@server1 ~]# kubectl apply -f daemonset.yaml
daemonset.apps/daemonset-example created
[root@server1 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
daemonset-example-ctbgh 1/1 Running 0 6m5s
daemonset-example-mdqzk 1/1 Running 0 6m5s
[root@server1 ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
daemonset-example-ctbgh 1/1 Running 0 7m16s 10.244.2.32 server3 <none> <none>
daemonset-example-mdqzk 1/1 Running 0 7m16s 10.244.1.25 server2 <none> <none>
可以看出我們的每個(gè)節(jié)點(diǎn)(server3和server2)上都運(yùn)行了一個(gè)pod
3、刪除一個(gè)pod:
[root@server1 ~]# kubectl delete pod daemonset-example-ctbgh
pod "daemonset-example-ctbgh" deleted
[root@server1 ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
daemonset-example-998ck 0/1 ContainerCreating 0 8s <none> server3 <none> <none>
daemonset-example-mdqzk 1/1 Running 0 8m22s 10.244.1.25 server2 <none> <none>
[root@server1 ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
daemonset-example-998ck 1/1 Running 0 24s 10.244.2.33 server3 <none> <none>
daemonset-example-mdqzk 1/1 Running 0 8m38s 10.244.1.25 server2 <none> <none>
可以看出刪除后DaemonSet控制器又會(huì)幫我們創(chuàng)建pod,以保證每個(gè)節(jié)點(diǎn)運(yùn)行一個(gè)pod。
實(shí)驗(yàn)后刪除:
[root@server1 ~]# kubectl delete -f daemonset.yaml
daemonset.apps "daemonset-example" deleted
Job控制器舉例
1、編輯yaml
Job控制器只運(yùn)行一次
[root@server1 ~]# vim job.yaml
[root@server1 ~]# cat job.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: pi
spec:
template:
spec:
containers:
- name: pi
image: perl #利用perl計(jì)算圓周率
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
restartPolicy: Never
backoffLimit: 4 #容器啟動(dòng)失敗重啟4次之后不再重啟。
2、創(chuàng)建
kubectl apply -f job.yaml
由于Job只運(yùn)行一次,因此運(yùn)行完后狀態(tài)為Completed,我們可以查看日志獲取結(jié)果:
可以看出計(jì)算成功。
實(shí)驗(yàn)后刪除:
[root@server1 ~]# kubectl delete -f job.yaml
job.batch "pi" deleted
CronJob控制器舉例
CronJob控制器用于定時(shí)執(zhí)行任務(wù):
[root@server1 ~]# vim cronjob.yaml
[root@server1 ~]# cat cronjob.yaml
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: cronjob-example
spec:
schedule: "* * * * "
jobTemplate:
spec:
template:
spec:
containers:
- name: cronjob
image: busybox
args:
- /bin/sh
- -c
- date; echo Hello from k8s cluster #輸出信息
restartPolicy: OnFailure
Crontab
其中schedule字段與crontab里面的寫(xiě)法相同," * * * *"表示每分鐘執(zhí)行任務(wù)。
1、創(chuàng)建pod:
[root@server1 ~]# kubectl apply -f cronjob.yaml
cronjob.batch/cronjob-example created
root@server1 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
cronjob-example-1587387120-ngt6n 0/1 ContainerCreating 0 16s
[root@server1 ~]# kubectl get pod #等待一分鐘
NAME READY STATUS RESTARTS AGE
cronjob-example-1587387120-ngt6n 0/1 Completed 0 60s
cronjob-example-1587387180-hbwzb 0/1 ContainerCreating 0 9s
可以看出每分鐘運(yùn)行一個(gè)pod,查看日志獲取輸出信息:
[root@server1 ~]# kubectl logs cronjob-example-1587387120-ngt6n
Mon Apr 20 12:52:30 UTC 2020
Hello from k8s cluster
[root@server1 ~]# kubectl logs cronjob-example-1587387180-hbwzb
Mon Apr 20 12:53:35 UTC 2020
Hello from k8s cluster
可以看出輸出也是每分鐘輸出一次,也可以使用以下命令查看cronjob的信息:
[root@server1 ~]# kubectl get cronjobs
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
cronjob-example * * * * * False 1 16s 3m10s
[root@server1 ~]# kubectl get job -w #查看job信息并且持續(xù)輸出
NAME COMPLETIONS DURATION AGE
cronjob-example-1587387120 1/1 20s 2m23s
cronjob-example-1587387180 1/1 35s 92s
cronjob-example-1587387240 1/1 20s 32s
實(shí)驗(yàn)后刪除
[root@server1 ~]# kubectl delete -f cronjob.yaml
cronjob.batch "cronjob-example" deleted
猜你喜歡:
Docker stack 一鍵編排Inmp【linux云計(jì)算+運(yùn)維開(kāi)發(fā)】
2020-04-29CentOS7的Chrony系統(tǒng)時(shí)鐘如何同步?【linux云計(jì)算+運(yùn)維開(kāi)發(fā)】
2020-04-2910分鐘創(chuàng)建阿里云容器服務(wù)kubernetes專(zhuān)有版?【IT運(yùn)維培訓(xùn)】
2020-04-29如何安裝配置Supervisor?【運(yùn)維培訓(xùn)】
2020-04-28Kubernetes是什么?Kubernetes網(wǎng)絡(luò)模型介紹
2020-04-04怎么使用U盤(pán)在物理機(jī)安裝centos系統(tǒng)?
2020-04-04