之前我们共使用两种方式创建 Pod。一种是 kubectl run,另一种为 kubectl create + 配置文件。当我们将以 kubectl create 创建的 Pod 删除之后,Pod 是不会重新被创建的,也就是说此类 Pod 是没有被控制器管理的,删除之后就没有了。而使用 kubectl run 创建的 Pod 是被控制器管理的,删除之后还会重新启动,达到你定义的状态。ReplicationController 是K8s之前的唯一一个控制器,因为其太过庞大,所以目前不怎么使用。从而出现的 ReplicaSet 等控制器成为主流。
ReplicaSet
查看定义
Kubernetes 并不建议我们直接使用 ReplicaSet 控制器。而是建议我们使用 Deployment 控制器。Deployment 通过控制 ReplicaSet 来控制 Pod,是对 ReplicaSet 的进一步封装,拥有更强大的功能。
查看 ReplicaSet 的字段
1 | kubectl explain rs |
ReplicaSet 的 spec 中有三个核心的部分组成,分别为副本数(replicas),标签选择器(selector),Pod 模版(template)。template 中 spec 的定义和我们之前定义的 Pod 方式一致,都有什么 containers,nodeName,nodeSelector等等。
1 | kubectl explain rs.spec |
创建资源
定义一个 ReplicaSet,标签选择规则为 matchLabels(所有标签都必须满足)。注意,这里创建的 Pod 的标签要和 ReplicaSet标签选择器中的一致,这样才能将创建出来的 Pod 和选择器进行关联。
1 | apiVersion: apps/v1 |
创建 Pod1
kubectl create -f rs-demo.yaml
查看 ReplicaSet。可以看到期待的两个,当前为两个,处于 READY 装状态的为两个。1
kubectl get rs
1 | [root@k8s001 rexyan]# kubectl get rs |
查看 Pod 列表(注意,Pod 的 name 是以控制器的名称加上随机字符串组成,而不是自己的定义的 myapp-pod)
1 | kubectl get pods |
1 | [root@k8s001 rexyan]# kubectl get pods |
查看 Pod 详细信息
1 | kubectl describe pods + pod 名称 |
1 | [root@k8s001 rexyan]# kubectl describe pods myapp-hl4wg |
查看 pods 的标签
1 | kubectl get pods --show-labels |
1 | [root@k8s001 rexyan]# kubectl get pods --show-labels |
修改标签
删除名称为 myapp-hl4wg 的 Pod,会看到一个新的 Pod 会被创建出来,因为我们期待的数量为 2 个。
1 | [root@k8s001 rexyan]# kubectl get pods --show-labels |
修改其中一个 Pod 的标签,将其 app=myapp 改为 app=app。会看到会新建一个 Pod 起来,被修改 Pod 现在就不属于任何控制器了。
1 | [root@k8s001 rexyan]# kubectl label pods myapp-d6q5r app=app --overwrite |
动态扩容
动态修改 ReplicaSet。myapp 为 ReplicaSet 的名称,并且副本为改成 5 个。改完后就会立即生效。
1 | [root@k8s001 rexyan]# kubectl edit rs myapp |
1 | [root@k8s001 rexyan]# kubectl get pods --show-labels |
或者使用 scale 命令进行修改
1 | [root@k8s001 rexyan]# kubectl scale --replicas=2 rs myapp |
滚动升级
使用 edit 编辑镜像版本之后,Pod 是不会自动更新的,我们需要将 Pod 删除,然后让其自动重新构建,这样构建出来的才是新版镜像版本的 Pod。这里有两种方式,让其服务过度到新镜像版本的服务,第一种为一个一个的删除 Pod,让其重新一个一个的构建。另一种为构建一个新的 ReplicaSet,测试没问题后,在将新的 ReplicaSet 挂载到 Service 上去,并将以前老的 ReplicaSet 在 service 上摘除。Deployment 就是采用的第二种思想,Deployment 可以管理多个 ReplicaSet,但是可用的只有一个,这样也可以进行回滚。
1 | kubectl edit rs myapp |
将其中镜像版本从 v1 改为 v2 ,查看 rs 信息,发现镜像版本已经变成了v2,但是访问结果去还是 v1,这时需要重建 Pod 才能生效。
1 | [root@k8s001 rexyan]# kubectl get rs -o wide |
或者选择之前的命令 set image 进行镜像升级。
Deployment
Deployment 是目前用来管理无状态应用的做好的控制器。deployment 简称为 deploy。 deploy.spec.strategy 表示更新策略,deploy.spec.strategy.type 支持两种更新,分别为 Recreate (重新创建) 和 RollingUpdate(滚动更新)默认是 RollingUpdate。当 deploy.spec.strategy.type 是 RollingUpdate 时,还可以配置 deploy.spec.strategy.type.RollingUpdate 字段,这个字段用来控制更新力度,共有两种值,分别为 maxSurge(更新过程中,超出目标副本数的数量,可为数字或者百分比) 和 maxUnavailable (最多有几个不可用)。我们可以控制这里的更新力度来实现不同的发布,例如金丝雀发布,蓝绿发布等。deploy.spec.revisionHistoryLimit 表示滚动更新中最多保存过去几个历史版本,这些历史版本可用于回滚。deployment 通过控制 ReplicaSet 来控制 Pod。
创建资源
1 | apiVersion: apps/v1 |
创建 deploy, apply 属于声明式创建,既可以创建,也可以用于更新。
1 | [root@k8s001 rexyan]# kubectl apply -f deploy-demo.yaml |
查看 deploy 会发现刚刚的已经创建好了
1 | [root@k8s001 rexyan]# kubectl get deploy |
查看 ReplicaSet 也会看到对应的两个,因为 deployment 是依赖 ReplicaSet 的,基于 ReplicaSet 之上。后面的 67b6dfcd8 模版的 hash值,而不是随机的字符串。1
2
3[root@k8s001 rexyan]# kubectl get rs
NAME DESIRED CURRENT READY AGE
myapp-deploy-67b6dfcd8 2 2 2 6m33s
查看 Pod, Pod 的名称是 myapp-deploy-67b6dfcd8-xxxx,格式为 deployment 的名字 + ReplicaSet hash + 随机数。
1 | [root@k8s001 rexyan]# kubectl get pods |
修改副本数
修改 yaml 脚本
1 | apiVersion: apps/v1 |
之后查看 Pod 的信息,发现名称部分 myapp-deploy-67b6dfcd8 依然没有变化,1
2[root@k8s001 rexyan]# kubectl apply -f deploy-demo.yaml
deployment.apps/myapp-deploy configured
1 | [root@k8s001 rexyan]# kubectl get pods |
查看 deploy 的详细信息
1 | [root@k8s001 rexyan]# kubectl describe deploy myapp-deploy |
apply 会自动将每一次版本的变化添加到 Annotations 当中。apply 的 StrategyType(更新方式)RollingUpdate(滚动更新)且最多可用和最多不可用分别为 RollingUpdateStrategy: 25% max unavailable, 25% max surge。
滚动更新
deploy 的 apply 方式更新,Pod 最大可以用和不可用的数量分别是 25%。我们可以使用 -w命令来查看整个更新的过程。
终端1:编辑配置文件,将副本数量调整为5 (当前为3)
1 | [root@k8s001 rexyan]# vim deploy-demo.yaml |
1 | [root@k8s001 rexyan]# kubectl apply -f deploy-demo.yaml |
终端2:可以看到有创建了两个 Pod,以此来满足 5 个的数量。
1 | [root@k8s001 ~]# kubectl get pods -w |
如果此时再次修改配置文件,将镜像从 image: ikubernetes/myapp:v1 升级为 image: ikubernetes/myapp:v2,则现象为, 这个就是整个滚动更新的过程,可以看到 Pod 的整个创建和结束的过程。
1 | myapp-deploy-675558bfc5-g4j5t 0/1 Pending 0 0s |
这时查看 rs 的信息,就会看到有两个 rs。不同点在于镜像的版本一个是v1,期待个数,当前可以个数等全部为0,另一个版本为 v2。v1 的存在是让我们可以回滚。
1 | [root@k8s001 rexyan]# kubectl get rs -o wide |
金丝雀发布
修改更新过程中最大更新数(max surge)为 1个, 最大可减少数(max unavailable)为 0 ,这就意味着,在目前已经有的 Pod 的基础上,最多可以存在 6 个Pod,最少那就是 5 个。这时我们要实现当其创建出地 6 个的时候,将其发布暂停(此时有1个新的,5个旧的)那一个新的服务其实就是创建出的金丝雀。确认金丝雀没问题之后,让刚刚暂停住的更新继续执行,完成发布。
1. 修改 yaml 文件
1 | apiVersion: apps/v1 |
1 | [root@k8s001 rexyan]# kubectl apply -f deploy-demo.yaml |
2. 查看详细信息, 发现已经修改了。
1 | [root@k8s001 rexyan]# kubectl describe deploy myapp-deploy |
3. 修改镜像版本为 v3,并让其执行更新之后暂停。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deploy
namespace: default
spec:
replicas: 5
selector:
matchLabels:
app: myapp
release: canary
template:
metadata:
labels:
app: myapp
release: canary
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v3
ports:
- name: http
containerPort: 80
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
执行更新,并且更新后暂定1
2
3[root@k8s001 rexyan]# kubectl apply -f deploy-demo.yaml && kubectl rollout pause deploy myapp-deploy
deployment.apps/myapp-deploy configured
deployment.extensions/myapp-deploy paused
可以看到最后一个 Pod 是新建出来的,并没有继续往下滚动更新执行删除,而是被暂停了。1
2
3
4
5
6
7
8[root@k8s001 rexyan]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-deploy-675558bfc5-4m4nb 1/1 Running 0 64m
myapp-deploy-675558bfc5-b2lj5 1/1 Running 0 64m
myapp-deploy-675558bfc5-g4j5t 1/1 Running 0 64m
myapp-deploy-675558bfc5-h8c2c 1/1 Running 0 64m
myapp-deploy-675558bfc5-kkl22 1/1 Running 0 64m
myapp-deploy-7f577979c8-v2ljw 1/1 Running 0 24s
这时可以确认 v3 版本的程序有没有问题(验证金丝雀),如果没有问题之后就可以继续执行更新过程。我们也可以查看更新过程。
1 | [root@k8s001 rexyan]# kubectl rollout status deploy myapp-deploy |
上面查看状态,显示的意思是,等待部署 myapp-deploy 5 个副本,已经完成了一个。
4. 继续执行更新
1 | [root@k8s001 rexyan]# kubectl rollout resume deploy myapp-deploy |
再次查看更新状态,发现提示已经更新完成了。1
2[root@k8s001 rexyan]# kubectl rollout status deploy myapp-deploy
deployment "myapp-deploy" successfully rolled out
查看 Pod,以前的老版本 Pod 都被删除了。1
2
3
4
5
6
7[root@k8s001 rexyan]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-deploy-7f577979c8-fbsvm 1/1 Running 0 26s
myapp-deploy-7f577979c8-mq26d 1/1 Running 0 30s
myapp-deploy-7f577979c8-r68x5 1/1 Running 0 27s
myapp-deploy-7f577979c8-v2ljw 1/1 Running 0 8m19s
myapp-deploy-7f577979c8-wpktg 1/1 Running 0 28s
查看 rs 的信息,发现 rs 已经有了三个,最新的为 v3 版本的镜像。1
2
3
4
5[root@k8s001 rexyan]# kubectl get rs -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
myapp-deploy-675558bfc5 0 0 0 72m myapp ikubernetes/myapp:v2 app=myapp,pod-template-hash=675558bfc5,release=canary
myapp-deploy-67b6dfcd8 0 0 0 118m myapp ikubernetes/myapp:v1 app=myapp,pod-template-hash=67b6dfcd8,release=canary
myapp-deploy-7f577979c8 5 5 5 8m42s myapp ikubernetes/myapp:v3 app=myapp,pod-template-hash=7f577979c8,release=canary
至此,就完成了一个金丝雀发布。
回滚操作
查看当前可以回滚的版本
1 | [root@k8s001 ~]# kubectl rollout history deploy myapp-deploy |
当前处于最新的第三个版本,我们可以使用 –to-revision 指定回退到的版本,例如回退到第一版本
1 | [root@k8s001 ~]# kubectl rollout undo deploy myapp-deploy --to-revision=1 |
再次查看 rollout history 会发现第一个版本已经没有了,对应的是第四个版本(其实这里的第四版本就是第一个版本)
1 | [root@k8s001 ~]# kubectl rollout history deploy myapp-deploy |
查看 rs的详细信息,也会发现当前版本已经回到了第一版
1 | [root@k8s001 ~]# kubectl get rs -o wide |
DaemonSet
在集群中的每一个节点或者满足条件的节点之上,有且仅运行一个 Pod 副本。DaemonSet 和 Deployment 一样,所控制的 Pod 也是无状态的,且两者应用一直在后台运行(就算是任务完成 Pod 也不能退出)。简称 ds
创建资源
创建资源,DaemonSet 在每一个 node 上只运行一个副本,所有不能指定 replicas, 其余的定义方式和 deploy 差不多,env 是定义环境变量,这里定义是因为镜像使用所需。
1 | apiVersion: apps/v1 |
1 | [root@k8s001 rexyan]# kubectl create -f ds-demo.yaml |
创建资源之后就可以看到在两个节点之上分别运行了一个 Pod1
2
3
4
5
6
7
8
9[root@k8s001 rexyan]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myapp-deploy-67b6dfcd8-42x9q 1/1 Running 0 45m 10.244.2.11 k8s003 <none> <none>
myapp-deploy-67b6dfcd8-9vjwh 1/1 Running 0 44m 10.244.1.17 k8s002 <none> <none>
myapp-deploy-67b6dfcd8-b45pt 1/1 Running 0 44m 10.244.2.13 k8s003 <none> <none>
myapp-deploy-67b6dfcd8-c2v69 1/1 Running 0 45m 10.244.1.16 k8s002 <none> <none>
myapp-deploy-67b6dfcd8-cr5hj 1/1 Running 0 44m 10.244.2.12 k8s003 <none> <none>
myapp-ds-kf892 1/1 Running 0 14s 10.244.2.14 k8s003 <none> <none>
myapp-ds-zb82c 1/1 Running 0 14s 10.244.1.18 k8s002 <none> <none>
更新方式
查看 ds 的更新策略可以发现,ds 支持 RollingUpdate(滚动更新) 和 OnDelete(删除后更新) 两种更新,默认为 OnDelete
1 | [root@k8s001 rexyan]# kubectl explain ds.spec.updateStrategy |
当 type 是 RollingUpdate 的时候,ds.spec.updateStrategy.rollingUpdate 下只能定义 maxUnavailable 字段。即只能定义最大可减少数(max unavailable)也就是只能删除后才能更新(这也符合 DaemonSet 在 Node 上只能有一个的原则)。
Job
按照用户的定义,完成指定任务,任务正常完成后 Pod 就会正常退出,若任务没有完成 Pod 就退出,则 Pod 会被重新创建。
CronJob
周期性运行
StatefulSet
有状态应用控制器
1 |