【Kubernetes】K8s笔记(八):Deployment 发布无状态的应用
1. Deployment API 对象
我们之前学习了 API 对象 Job 和 CronJob,它们代表了生产环境中的离线业务,通过对 Pod 的包装,向 Pod 添加控制字段,实现了基于 Pod 运行临时任务和定时任务的功能。
这次要学习的 API 对象名字叫 Deployment,顾名思义,它是专门用来部署应用程序的,能够让应用永不宕机,多用来发布无状态的应用,是 Kubernetes 里最常用也是最有用的一个对象。它也是由 Pod 衍生出来的 API 对象。
部署应用如果只使用 Pod 这个 API 对象,会有下列的问题:
-
虽然 Pod 可以在 YAML 文件里指定
containers
中的restartPolicy
字段在容器发生问题的时候自动重启容器,但是它无法处理手动删除 Pod 或者节点宕机导致的应用故障,这时候 Pod 就会从集群里彻底消失 -
在线业务还有很多复杂操作,比如多实例、高可用、更新等;如果只使用 Pod 这个 API 对象,就会回到手工管理容器的老路上,无法发挥 Kubernetes 自动化运维的优势
Deployment 就是一个新的用来管理 Pod,实现在线业务应用的 API 对象。
2. 使用 YAML 描述 Deployment
使用 kubectl api-resources
查看 Deployment 对象的基本信息:
NAME SHORTNAMES APIVERSION NAMESPACED KIND
deployments deploy apps/v1 true Deployment
Deployment 的简称是 deploy
,它的 apiVersion
是 apps/v1
,kind
是 Deployment
。
使用命令创建 Deployment 的 YAML 模板:名字叫 ngx-dep
,使用的镜像是 nginx:alpine
$ export out="--dry-run=client -o yaml"
$ kubectl create deploy ngx-dep --image=nginx:alpine $out
删除一些无用的配置项得到 YAML 模板如下:
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: ngx-dep
name: ngx-dep
spec:
replicas: 2
selector:
matchLabels:
app: ngx-dep
template:
metadata:
labels:
app: ngx-dep
spec:
containers:
- image: nginx:alpine
name: nginx
可以看到,Deployment 的 spec
多了 replicas
selector
这两个新字段。
关键字段 replicas
字段 replicas
用来设定副本数量,指定要在 Kubernetes 集群中运行多少个 Pod 实例。这个字段为 Kubernetes 明确提供了一个应用部署的期望状态,Deployment 对象可以根据这个字段自动地调整集群内的 Pod 数量。
比如,在 Deployment 对象刚创建出来的时候,Pod 数量肯定是 0,那么它就会根据 YAML 文件里的 Pod 模板,逐个创建出要求数量的 Pod。再比如,万一有 Pod 发生意外消失了,数量不满足“期望状态”,它就会通过 apiserver、scheduler 等核心组件去选择新的节点,创建出新的 Pod,直至数量与“期望状态”一致。
关键字段 selector
spec:
replicas: 2
selector:
matchLabels:
app: ngx-dep
template:
metadata:
labels:
app: ngx-dep
-
selector
的作用是筛选出被 Deployment 管理的 Pod 对象 -
selector
的下属字段matchLabels
定义了被管理的 Pod 对象应该携带的label
;matchLabels
必须和template
里 Pod 定义的labels
完全相同,否则 Deployment 就会找不到要控制的 Pod 对象,apiserver 也会告诉你 YAML 格式校验错误无法创建。
selector
字段的用法初看起来好像是有点多余,为了保证 Deployment 成功创建,我们必须在 YAML 里把 label
重复写两次:一次是在selector.matchLabels
,另一次是在 template.matadata
。
Deployment 和 Pod 实际上是一种松散的组合关系,Deployment 实际上并不“持有”Pod 对象,它只是帮助 Pod 对象能够有足够的副本数量运行。复杂的在线业务使得 Pod 除了要在 Deployment 里部署运行,还可能会被其他的 API 对象引用来管理,比如负责负载均衡的 Service 对象。
Kubernetes 采用“贴标签”的方式,通过在 API 对象的 metadata
里加各种标签(labels),让配置人员使用类似关系数据库里查询语句的方式,筛选出具有特定标识的那些对象。通过标签这种设计,Kubernetes 就解除了 Deployment 和模板里 Pod 的强绑定,把组合关系变成了“弱引用”。
3. 操作 Deployment
使用下面的命令创建 Deployment 对象:
$ kubectl apply -f deploy.yml
查看 Deployment 的状态:
$ kubectl get deploy -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
ngx-dep 2/2 2 2 54s nginx nginx:alpine app=ngx-dep
-
READY
表示运行的 Pod 数量,前面的数字是当前数量,后面的数字是期望数量,所以“2/2”的意思就是要求有两个 Pod 运行,现在已经启动了两个 Pod。 -
UP-TO-DATE
指的是当前已经更新到最新状态的 Pod 数量。因为如果要部署的 Pod 数量很多或者 Pod 启动比较慢,Deployment 完全生效需要一个过程,UP-TO-DATE 就表示现在有多少个 Pod 已经完成了部署,达成了模板里的“期望状态”。 -
AVAILABLE
要比READY
UP-TO-DATE
更进一步,不仅要求已经运行,还必须是健康状态,能够正常对外提供服务,它才是我们最关心的 Deployment 指标。最后一个AGE
就简单了,表示 Deployment 从创建到现在所经过的时间,也就是运行的时间。
查看 pod 的状态:
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ngx-dep-6b9d9dd879-qbtks 1/1 Running 1 (2m27s ago) 3m39s 10.10.1.12 worker1 <none> <none>
ngx-dep-6b9d9dd879-rc2th 1/1 Running 0 3m39s 10.10.1.10 worker1 <none> <none>
被 Deployment 管理的 Pod 自动带上了名字,命名的规则是 Deployment 的名字加上两串随机数(其实是 Pod 模板的 Hash 值)。
接下来我们手动删除 Pod 模拟 Pod 故障,然后查看 Pod:
$ kubectl delete pod ngx-dep-6b9d9dd879-qbtks
pod "ngx-dep-6b9d9dd879-qbtks" deleted
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ngx-dep-6b9d9dd879-8n2lx 1/1 Running 0 4s 10.10.1.23 worker1 <none> <none>
ngx-dep-6b9d9dd879-rc2th 1/1 Running 7 (15m ago) 33m 10.10.1.22 worker1 <none> <none>
可以看到新的 Pod 生成了。
在 Deployment 部署成功之后,我们还可以随时调整 Pod 的数量,实现所谓的“应用伸缩”。这项工作在 Kubernetes 出现之前对于运维来说是一件很困难的事情,而现在由于有了 Deployment 就变得轻而易举了。
比如下面的这条命令,就把 Nginx 应用扩容到了 5 个:
$ kubectl scale --replicas=5 deploy ngx-dep
但要注意, kubectl scale
是命令式操作,扩容和缩容只是临时的措施,如果应用需要长时间保持一个确定的 Pod 数量,最好还是编辑 Deployment 的 YAML 文件,改动 replicas
,再以声明式的 kubectl apply
修改对象的状态。
4. labels 字段的使用方法
之前我们通过 labels 为对象“贴”了各种“标签”,在使用 kubectl get
命令的时候,加上参数 -l
,使用 ==
!=
in
notin
的表达式,就能够很容易地用“标签”筛选、过滤出所要查找的对象(有点类似社交媒体的 #tag 功能),效果和 Deployment 里的 selector
字段是一样的。
看两个例子,第一条命令找出 app
标签是 nginx
的所有 Pod,第二条命令找出 app
标签是 ngx
、nginx
、ngx-dep
的所有 Pod:
$ kubectl get pod -l app=nginx
$ kubectl get pod -l 'app in (ngx, nginx, ngx-dep)'