本文作者:何文强 — CODING 高级解决方案架构师 具有一线互联网、物联网独角兽、全国股份制银行、新型智慧交通等跨行业从业经历,历任 Java 开发高级工程师、DevOps 技术专家、高级研发经理等职,对微服务、敏捷、DevOps、容器技术有深刻的理解和丰富的实践。
Pod 是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元。一个 Pod 有一个或多个容器组成,Pod 中容器共享存储和网络,在同一个 Node 节点上运行。
通常你不需要直接创建 Pod,甚至单实例 Pod。相反,你会使用诸如 Deployment 或 Job 这类工作负载资源来创建 Pod。如果 Pod 需要跟踪状态,可以考虑 StatefulSet 资源。
示例:
apiVersion: v1
kind: Pod
metadata:
name: static-web
labels:
role: myrole
spec:
containers:
- name: web
image: nginx
ports:
- name: web
containerPort: 80
protocol: TCP
Pod 阶段
取值 | 描述 |
---|---|
Pending(悬决) | Pod 已被 Kubernetes 系统接受,但有一个或者多个容器尚未创建亦未运行。此阶段包括等待 Pod 被调度的时间和通过网络下载镜像的时间。 |
Running(运行中) | Pod 已经绑定到了某个节点,Pod 中所有的容器都已被创建。至少有一个容器仍在运行,或者正处于启动或重启状态。 |
Succeeded(成功) | Pod 中的所有容器都已成功终止,并且不会再重启。 |
Failed(失败) | Pod 中的所有容器都已终止,并且至少有一个容器是因为失败终止。也就是说,容器以非 0 状态退出或者被系统终止。 |
Unknown(未知) | 因为某些原因无法取得 Pod 的状态。这种情况通常是因为与 Pod 所在主机通信失败。 |
容器状态
容器状态 | 描述 |
---|---|
Waiting(等待) | 如果容器并不处在 Running 或 Terminated 状态之一,它就处在 Waiting 状态。处于 Waiting 状态的容器仍在运行它完成启动所需要的操作:例如,从某个容器镜像 仓库拉取容器镜像,或者向容器应用 Secret数据等等。当你使用 kubectl 来查询包含 Waiting 状态的容器的 Pod 时,你也会看到一个 Reason 字段,其中给出了容器处于等待状态的原因。 |
Running(运行中) | Running 状态表明容器正在执行状态并且没有问题发生。如果配置了 postStart 回调,那么该回调已经执行且已完成。如果你使用 kubectl 来查询包含 Running 状态的容器的 Pod 时,你也会看到 关于容器进入 Running 状态的信息 |
Terminated(已终止) | 处于 Terminated 状态的容器已经开始执行并且或者正常结束或者因为某些原因失败。如果你使用 kubectl 来查询包含 Terminated 状态的容器的 Pod 时,你会看到 容器进入此状态的原因、退出代码以及容器执行期间的起止时间。如果容器配置了 preStop 回调,则该回调会在容器进入 Terminated 状态之前执行 |
Pod 的 spec 中包含一个 restartPolicy 字段,其可能取值包括 Always、OnFailure 和 Never。默认值是 Always。
容器探针
针对运行中的容器,kubelet 可以选择是否执行以下三种探针,以及如何针对探测结果作出反应。
指示容器是否正在运行。如果存活态探测失败,则 kubelet 会杀死容器, 并且容器将根据其重启策略决定未来。如果容器不提供存活探针, 则默认状态为 Success。
存活探针示例:
apiVersion: v1kind: Podmetadata: labels: test: liveness name: liveness-httpspec: containers: -name: liveness image: k8s.gcr.io/liveness args: - /server livenessProbe: httpGet: path: /healthz port:8080 httpHeaders: -name: Custom-Header value: Awesome initialDelaySeconds:3#第一次执行探针前等待3秒 periodSeconds:3#每隔3秒执行一次存活探针
指示容器是否准备好为请求提供服务。如果就绪态探测失败, 端点控制器将从与 Pod 匹配的所有服务的端点列表中删除该 Pod 的 IP 地址。初始延迟之前的就绪态的状态值默认为 Failure。如果容器不提供就绪态探针,则默认状态为 Success。
就绪探针(readlinessProbe)与存活探针(livenessProbe)配置一致,唯一区别在于就绪探针需要使用 readlinessProbe 字段,而不是 livenessProbe 字段。
apiVersion: v1kind: Podmetadata: labels: test: liveness name: liveness-httpspec: containers: -name: liveness image: k8s.gcr.io/liveness args: - /server readlinessProbe: httpGet: path: /healthz port:8080 httpHeaders: -name: Custom-Header value: Awesome initialDelaySeconds:3#第一次执行探针前等待3秒 periodSeconds:3#每隔3秒执行一次存活探针
指示容器中的应用是否已经启动。如果提供了启动探针,则所有其他探针都会被 禁用,直到此探针成功为止。如果启动探测失败,kubelet 将杀死容器,而容器依 重启策略进行重启。如果容器没有提供启动探测,则默认状态为 Success。
启动探针示例:
startupProbe: httpGet: path: /healthz port: liveness-port failureThreshold: 30 #故障阈值,最多允许 30 次 periodSeconds: 10 #每次间隔 10s
通过启动探针,应用程序将会有最多 5 分钟(30 x 10 = 300s)的时间来完成它的启动。一旦启动探测成功一次,存活探测任务就会接管对容器的探测,对容器死锁可以快速响应。如果启动探测一直没有成功,容器会在 300 秒后被杀死,并且根据 restartPolicy 来设置 Pod 状态。
Service 一个应用服务抽象,定义了 Pod 逻辑集合和访问这个 Pod 集合的策略,Service 通过 Lable Selector 选择一组 Pod 提供服务。
支持多种访问方式实现:
Service 和 Pod 通过标签选择器 Label 进行关联,在同一个 namespace 下,Kubernetes 会自动去匹配具有相同标签的 Service 和 Pod。
标签用于区分对象(比如 Pod、Service),键/值对存在;每个对象可以有多个标签,通过标签关联对象。
示例:
Service 通过 Label 与后端 pod 进行关联,Deploment 文件里 Pod label(spec.template.metadata.labels)为 run: my-nginx,而对应 Service(spec.selector)的 selector 刚好同为 run: my-nginx,这样便通过 label 将 Service 于后端 Pod 进行关联,label 生效范围是 service 和 deployment 在同一个 namespcae 有效,不填写 namespace 则默认为 default namespace。
命名空间(namespace)也称为虚拟集群,Kubernetes 命名空间将对象逻辑上分配到不同 Namespace,可以是不同的项目、用户等区分管理,并设定控制策略,从而实现多租户。
Kubernetes 会创建四个
初始化 namespace
没有指明使用其它名字空间的对象所使用的默认名字空间。
Kubernetes 系统创建对象所使用的名字空间。
这个名字空间是自动创建的,所有用户(包括未经过身份验证的用户)都可以读取它。这个名字空间主要用于集群使用,以防某些资源在整个集群中应该是可见和可读的。这个名字空间的公共方面只是一种约定,而不是要求。
此名字空间用于与各个节点相关的 租约(Lease)对象。节点租期允许 kubelet 发送心跳,由此控制面能够检测到节点故障。
示例:my-namespace.yaml
apiVersion: v1kind: Namespacemetadata: name: my-namespace
ReplicaSet 的目的是维护一组在任何时候都处于运行状态的 Pod 副本的稳定集合。因此,它通常用来保证给定数量的、完全相同的 Pod 的可用性。
示例:frontend.yaml
apiVersion: apps/v1kind: ReplicaSetmetadata: name: frontend labels: app: guestbook tier: frontendspec: # modify replicas according to your case replicas:3 selector: matchLabels: tier: frontend template: metadata: labels: tier: frontend spec: containers: -name: php-redis image: gcr.io/google_samples/gb-frontend:v3
frontend.yaml 中定义了对象类型为 Replicaset,replicas=3,执行 kubectl apply -f frontend.yaml 时,会创建 3 个类型为 Replicaset的frontend 副本。
Deployment 是一个更高层次的 API 对象,它管理 ReplicaSets 和 Pod,并提供声明式更新等功能。Deployment=Pod+Replicaset。
示例:nginx-deployment.yaml
apiVersion: apps/v1kind: Deploymentmetadata: name: nginx-deployment labels: app: nginxspec: replicas:3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: -name: nginx image: nginx:1.14.2 ports: -containerPort:80
StatefulSet 是用来管理有状态应用的工作负载 API 对象。StatefulSet 适合持久性的应用程序,有唯一的网络标识符(IP),持久储存,有序的部署、扩展、删除和滚动更新。StatefulSets 适用于有以下需求的应用程序:
示例:web.yaml
apiVersion: v1kind: Servicemetadata: name: nginx labels: app: nginxspec: ports: -port:80 name: web clusterIP: None selector: app: nginx---apiVersion: apps/v1kind: StatefulSetmetadata: name: webspec: selector: matchLabels: app: nginx # has to match .spec.template.metadata.labels serviceName:"nginx" replicas:3# by default is 1 template: metadata: labels: app: nginx # has to match .spec.selector.matchLabels spec: terminationGracePeriodSeconds:10 containers: -name: nginx image: k8s.gcr.io/nginx-slim:0.8 ports: -containerPort:80 name: web volumeMounts: -name: www mountPath: /usr/share/nginx/html volumeClaimTemplates: -metadata: name: www spec: accessModes:["ReadWriteOnce"] storageClassName:"my-storage-class" resources: requests: storage: 1Gi
在示例中:
适用于在所有节点或部分节点运行一个 daemon 守护进程,DaemonSet 的一些典型用法:
示例:fluentd-elasticsearch.yaml
apiVersion: apps/v1kind: DaemonSetmetadata: name: fluentd-elasticsearch namespace: kube-system labels: k8s-app: fluentd-loggingspec: selector: matchLabels: name: fluentd-elasticsearch template: metadata: labels: name: fluentd-elasticsearch spec: tolerations: # this toleration is to have the daemonset runnable on master nodes # remove it if your masters can't run pods -key: node-role.kubernetes.io/master operator: Exists effect: NoSchedule containers: -name: fluentd-elasticsearch image: quay.io/fluentd_elasticsearch/fluentd:v2.5.2 resources: limits: memory: 200Mi requests: cpu: 100m memory: 200Mi volumeMounts: -name: varlog mountPath: /var/log -name: varlibdockercontainers mountPath: /var/lib/docker/containers readOnly:true terminationGracePeriodSeconds:30 volumes: -name: varlog hostPath: path: /var/log -name: varlibdockercontainers hostPath: path: /var/lib/docker/containers
一次性任务,运行完成后 Pod 销毁,不再重新启动新容器。
示例:pi-job.yaml
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
CronJob 创建基于时隔重复调度的 Jobs。一个 CronJob 对象就像 crontab (cron table) 文件中的一行。它用 Cron 格式进行编写, 并周期性地在给定的调度时间执行 Job。
示例:hello-cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: hello
spec:
schedule: "*/1 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox
imagePullPolicy: IfNotPresent
command:
- /bin/sh
- -c
- date; echo Hello from the Kubernetes cluster
restartPolicy: OnFailure
示例为每分钟执行一次 date; echo Hello from the Kubernetes cluster 命令。
Cron 时间语法:
# ┌───────────── 分钟 (0 - 59)
# │ ┌───────────── 小时 (0 - 23)
# │ │ ┌───────────── 月的某天 (1 - 31)
# │ │ │ ┌───────────── 月份 (1 - 12)
# │ │ │ │ ┌───────────── 周的某天 (0 - 6)
# │ │ │ │ │
# │ │ │ │ │
# │ │ │ │ │
# * * * * *
CronJob 限制
CronJob 根据其计划编排,在每次该执行任务的时候大约会创建一个 Job。我们之所以说“大约”,是因为在某些情况下,可能会创建两个 Job,或者不会创建任何 Job。我们试图使这些情况尽量少发生,但不能完全杜绝。因此,Job 应该是幂等的。
《数字化 IT 从业者知识体系》背景
数字化和可持续发展是中国企业未来发展的两大主题,掌握数字化知识,具备数字化能力,应用数字化技术是我们 IT 从业者未来核心竞争力所在。《数字化 IT 从业者知识体系》的初衷是为 IT 从业者提供的系统性的数字化知识体系,内容涵盖管理实践、工程实践、技术实践三个层次,涉及软件开发方法、应用技术架构、应用部署与管理、软件交付与协作四大方面。
在接下来的《数字化 IT 从业者知识体系》系列文章,何文强将从软件开发方法、应用技术架构、应用部署与管理、软件交付与协作四个方面,为大家进行逐一分享介绍:
1. 软件开发方法主要包括瀑布、敏捷、精益等;
2. 应用技术架构主要包括微服务架构、服务网格架构、无服务器架构、分布式多运行架构等;
3. 应用部署与管理主要包括但不限于虚拟化技术、容器技术与容器编排等;
4. 软件交付与协作主要包括但不限于 CMMI、ITIL、DevOps 等。
相信该知识体系有利于 IT 从业者构建丰富的技术体系、全面的技术视野和系统的能力建设。欢迎大家前往《数字化 IT 从业者知识体系》话题进行详细阅读。