Controller与Service系列(一) Controller基本概念
一、简介
控制器(Controller)是集群上管理和运行容器的对象。Pod就是通过Controller实现应用的运维,如伸缩、滚动升级等,其中Pod与Controller之间通过标签(Label)以及标签选择器(Selector)建立关联。
控制器(Controller)对象有不同的类型,比较常用的有:
- Deployment 使用它可以进行应用的部署、应用的升级回滚、弹性伸缩等。
- StatefulSet 管理有状态应用,用来管理某 Pod集合的部署和扩缩, 并为这些 Pod 提供持久存储和持久标识符。
- DaemonSet 确保全部(或者某些)节点上运行一个 Pod 的副本。
- Job 一次性任务
- CronJob 创建基于时隔重复调度的 Jobs
二、Deployment
(一)应用部署
Deployment常用的场景就是应用的部署、升级、回滚、伸缩等。
1、部署准备
在之前的操作中直接通过命令行的方式进行应用的部署:
[root@k8smaster ~]# kubectl create development web --image=nginx
但是这样不利于重用,所以可以采用yaml文件的方式:
# 导出yaml文件 [root@k8smaster ~]# kubectl create deployment web --image=nginx --dry-run -o yaml > web.yam
可以看到yaml文件中的内容:
apiVersion: apps/v1 kind: Deployment metadata: creationTimestamp: null labels: app: web name: web spec: replicas: 1 selector: matchLabels: app: web strategy: {} template: metadata: creationTimestamp: null labels: app: web spec: containers: - image: nginx name: nginx resources: {} status: {}
可以看到Deployment控制器中的selector中与Pod中的labels进行匹配,它们之间就是基于此进行关联。
2、yaml部署
[root@k8smaster ~]# kubectl apply -f web.yaml deployment.apps/web created
目前该应用只能集群内部访问,需要暴露端口到外部,这样外部才能访问。
3、应用发布(对外暴露端口)
# 导出yaml文件 [root@k8smaster ~]# kubectl expose deployment web --port=80 --type=NodePort --target-port=80 --name=webOut -o yaml > webOut.yaml
apiVersion: v1 kind: Service metadata: creationTimestamp: "2021-06-18T18:11:36Z" labels: app: web managedFields: - apiVersion: v1 fieldsType: FieldsV1 fieldsV1: f:metadata: f:labels: .: {} f:app: {} f:spec: f:externalTrafficPolicy: {} f:ports: .: {} k:{"port":80,"protocol":"TCP"}: .: {} f:port: {} f:protocol: {} f:targetPort: {} f:selector: .: {} f:app: {} f:sessionAffinity: {} f:type: {} manager: kubectl operation: Update time: "2021-06-18T18:11:36Z" name: web1 namespace: default resourceVersion: "393318" selfLink: /api/v1/namespaces/default/services/web1 uid: 9cbe6be0-d147-43a4-812f-32ae6722fdf3 spec: clusterIP: 10.97.65.66 externalTrafficPolicy: Cluster ports: - nodePort: 31681 port: 80 protocol: TCP targetPort: 80 selector: app: web sessionAffinity: None type: NodePort status: loadBalancer: {}
进行部署:
[root@k8smaster ~]# kubectl apply -f web1.yaml # 查看 [root@k8smaster ~]# kubectl get pods,svc NAME READY STATUS RESTARTS AGE pod/web-5dcb957ccc-j2pg4 1/1 Running 0 15m NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 61d service/web1 NodePort 10.97.65.66 <none> 80:31681/TCP 3m51s
(二)应用升级、回滚
1、应用升级
# 升级 [root@k8smaster ~]# kubectl set image deployment web nginx=nginx:1.15 deployment.apps/web image updated # 查看升级状态 [root@k8smaster ~]# kubectl rollout status deployment web deployment "web" successfully rolled out
2、应用回滚
# 查看回滚版本 [root@k8smaster ~]# kubectl rollout history deployment web deployment.apps/web REVISION CHANGE-CAUSE 1 <none> 2 <none> # 回滚到上一个版本 [root@k8smaster ~]# kubectl rollout undo deployment web deployment.apps/web rolled back # 回滚到指定版本 [root@k8smaster ~]# kubectl rollout undo deployment web --to-revision=2
(三)弹性伸缩
# 伸缩前查看 [root@k8smaster ~]# kubectl get pods,svc NAME READY STATUS RESTARTS AGE pod/web-5dcb957ccc-66txn 1/1 Running 0 3m5s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 61d service/web1 NodePort 10.97.65.66 <none> 80:31681/TCP 40m # 进行伸缩 [root@k8smaster ~]# kubectl scale deployment web --replicas=3 deployment.apps/web scaled # 伸缩后查看 [root@k8smaster ~]# kubectl get pods,svc NAME READY STATUS RESTARTS AGE pod/web-5dcb957ccc-66txn 1/1 Running 0 3m41s pod/web-5dcb957ccc-jx4kl 0/1 ContainerCreating 0 2s pod/web-5dcb957ccc-zvmcm 0/1 ContainerCreating 0 2s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 61d service/web1 NodePort 10.97.65.66 <none> 80:31681/TCP 41m
三、StatefulSet
StatefulSet 用来管理某 Pod 集合的部署和扩缩, 并为这些 Pod 提供持久存储和持久标识符。所以相对于Deployment而言它是有状态的,需要考虑下面的情况:
- 保持每个Pod独立、启动顺序、唯一性
- 唯一的网络标识、持久存储
创建StatefulSet:
apiVersion: v1 kind: Service metadata: name: nginx labels: app: nginx spec: ports: - port: 80 name: web clusterIP: None selector: app: nginx --- apiVersion: apps/v1 kind: StatefulSet metadata: name: nginx-statefulset namespace: default spec: serviceName: nginx replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:latest ports: - containerPort: 80
它创建了一个 Headless Service nginx用来发布 StatefulSet web中的 Pod 的 IP 地址,表现形式就是clusterIP为None。执行上面的yaml文件:
[root@k8smaster ~]# kubectl apply -f statefulset.yaml service/nginx created
上面创建两个Pod的副本,但是它是按照{0,N-1}的顺序来创建Pod的,也就是Pod是有顺序的。
其次查看创建的两个Pod:
[root@k8smaster ~]# kubectl get pods NAME READY STATUS RESTARTS AGE nginx-statefulset-0 1/1 Running 0 15m nginx-statefulset-1 1/1 Running 0 14m
每个都是有唯一的名称,最后看一下网络标识,每个 Pod 都拥有一个基于其顺序索引的稳定的主机名。使用kubectl exec在每个 Pod 中执行hostname。
[root@k8smaster ~]# for i in 0 1; do kubectl exec "nginx-statefulset-$i" -- sh -c 'hostname'; done nginx-statefulset-0 nginx-statefulset-1
四、DaemonSet
DaemonSet 确保全部(或者某些)节点上运行一个 Pod 的副本。 当有节点加入集群时, 也会为他们新增一个 Pod 。 当有节点从集群移除时,这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod
DaemonSet 的一些应用场景:
- 在每个节点上运行集群守护进程
- 在每个节点上运行日志收集守护进程
- 在每个节点上运行监控守护进程
创建 一个日志收集工具的DaemonSet:
apiVersion: apps/v1 kind: DaemonSet metadata: name: ds-test labels: app: filebeat spec: selector: matchLabels: app: filebeat template: metadata: labels: app: filebeat spec: containers: - name: logs image: nginx ports: - containerPort: 80 volumeMounts: - name: varlog mountPath: /tmp/log volumes: - name: varlog hostPath: path: /var/log
执行该yaml文件:
[root@k8smaster ~]# kubectl apply -f ds.yaml daemonset.apps/ds-test created
可以看到在各个node节点上已经部署了Pod:
[root@k8smaster ~]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES ds-test-6qdwg 1/1 Running 0 84s 10.244.1.23 k8snode1 <none> <none> ds-test-m79px 1/1 Running 0 84s 10.244.2.20 k8snode2 <none> <none>
进入到某个Pod中进行查看:
[root@k8smaster ~]# kubectl exec -it ds-test-6qdwg bash kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl kubectl exec [POD] -- [COMMAND] instead. root@ds-test-6qdwg:/# ls /tmp/log/ anaconda btmp-20210617 dmesg maillog pods secure-20210617 tuned audit containers dmesg.old maillog-20210617 ppp spooler vmware-vmsvc.log boot.log cron firewalld messages rhsm spooler-20210617 wtmp btmp cron-20210617 lastlog messages-20210617 secure tallylog yum.log
五、Job
Job 会创建一个或者多个 Pods,并将继续重试 Pods 的执行,直到指定数量的 Pods 成功终止。 随着 Pods 成功结束,Job 跟踪记录成功完成的 Pods 个数。 当数量达到指定的成功个数阈值时,任务(即 Job)结束。 删除 Job 的操作会清除所创建的全部 Pods。 挂起 Job 的操作会删除 Job 的所有活跃 Pod,直到 Job 被再次恢复执行。
下面是一个 Job 配置示例。它负责计算 π 到小数点后 2000 位,并将结果打印出来。
apiVersion: batch/v1 kind: Job metadata: name: pi spec: template: spec: containers: - name: pi image: perl command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"] restartPolicy: Never backoffLimit: 4
执行:
[root@k8smaster ~]# kubectl apply -f job.yaml job.batch/pi created
查看Pod状态:
# 因为是一次性任务,所以执行后即结束 [root@k8smaster ~]# kubectl get pods NAME READY STATUS RESTARTS AGE pi-vbmwk 0/1 Completed 0 4m26s
查看结果:
[root@k8smaster ~]# kubectl logs pi-vbmwk 3.14159265358979323846264338327950...
六、CronJob
CronJobs 对于创建周期性的、反复重复的任务很有用,例如执行数据备份或者发送邮件。 CronJobs 也可以用来计划在指定时间来执行的独立任务,例如计划当集群看起来很空闲时 执行某个 Job。如下实例:
apiVersion: batch/v1beta1 kind: CronJob metadata: name: hello spec: schedule: "*/1 * * * *" jobTemplate: spec: template: spec: containers: - name: hello image: busybox args: - /bin/sh - -c - date; echo Hello from the Kubernetes cluster restartPolicy: OnFailure
执行:
[root@k8smaster ~]# kubectl apply -f cronjob.yaml cronjob.batch/hello created
可以看到周期性的调用:
[root@k8smaster ~]# kubectl get pods NAME READY STATUS RESTARTS AGE hello-1624090140-w8xcn 0/1 Completed 0 2m57s hello-1624090200-m2lng 0/1 ContainerCreating 0 2m21s hello-1624090260-bwhjj 0/1 ContainerCreating 0 80s hello-1624090320-bcd7b 0/1 ContainerCreating 0 20s
查看某个Pod里面的内容:
[root@k8smaster ~]# kubectl logs hello-1624090140-w8xcn Sat Jun 19 08:11:44 UTC 2021 Hello from the Kubernetes cluster