我们已经知道k8s是通过各种controller来管理pod的生命周期。为了满足不同业务场景,k8s开发了Deployment、ReplicaSet、DaemonSet、StatefuleSet、Job等多种 Controller。我们首先学习最常用的 Deployment。
运行一个deployment[root@ken ~]/# kubectl run httpd-ken1--generator=run-pod/v1 --image=httpd --replicas=2
下面详细分析 Kubernetes 都做了些什么工作。[root@ken ~]/# kubectl getdeployment NAME READY UP-TO-DATE AVAILABLE AGE httpd-ken 2/2 2 2 35m
kubectl get deplouyment命令可以查看 httpd-ken 的状态,输出显示两个副本正常运行。
接下来我们用 kubectl describe deployment 了解更详细的信息。[root@ken ~]/# kubectl describe deployment httpd-ken Name: httpd-ken Namespace:defaultCreationTimestamp: Tue,29 Jan 2019 15:27:40 +0800Labels: run=httpd-ken Annotations: deployment.kubernetes.io/revision: 1Selector: run=httpd-ken Replicas:2 desired | 2 updated | 2 total | 2 available | 0unavailable StrategyType: RollingUpdate MinReadySeconds:0RollingUpdateStrategy:25% max unavailable, 25%max surge Pod Template: Labels: run=httpd-ken Containers: httpd-ken: Image: httpd Port:
大部分内容都是自解释的,我们重点看最下面部分。这里告诉我们创建了一个 ReplicaSet httpd-ken-5c949b96,Events是 Deployment的日志,记录了 ReplicaSet的启动过程。
通过上面的分析,也验证了 Deployment 通过 ReplicaSet来管理 Pod的事实。接着我们将注意力切换到 httpd-ken-5c949b96,执行 kubectl describe replicaset:[root@ken ~]/# kubectl getreplicaset NAME DESIRED CURRENT READY AGE httpd-ken-5c949b96f 2 2 2 20m
两个副本已经就绪,用 kubectl describe replicaset 查看详细信息:
[root@ken ~]/# kubectl describe replicaset Name: httpd-ken-5c949b96f Namespace:defaultSelector: pod-template-hash=5c949b96f,run=httpd-ken Labels: pod-template-hash=5c949b96f run=httpd-ken Annotations: deployment.kubernetes.io/desired-replicas: 2deployment.kubernetes.io/max-replicas: 3deployment.kubernetes.io/revision: 1Controlled By: Deployment/httpd-ken Replicas:2 current / 2desired Pods Status:2 Running / 0 Waiting / 0 Succeeded / 0Failed Pod Template: Labels: pod-template-hash=5c949b96f run=httpd-ken Containers: httpd-ken: Image: httpd Port:
Controlled By 指明此 ReplicaSet 是由 Deployment httpd-ken 创建。Events 记录了两个副本 Pod 的创建。接着我们来看 Pod,执行 kubectl get pod:[root@ken ~]/# kubectl getpod NAME READY STATUS RESTARTS AGE httpd-ken-5c949b96f-9cd52 1/1 Running 022m httpd-ken-5c949b96f-twdsd 1/1 Running 0 22m
两个副本 Pod 都处于 Running状态,用 kubectl describe pod查看更详细的信息:root@ken ~]/# kubectl describe pod Name: httpd-ken-5c949b96f-9cd52 Namespace:defaultPriority:0PriorityClassName:
Controlled By 指明此 Pod 是由 ReplicaSet httpd-ken-5c949b96f创建。Events 记录了 Pod 的启动过程。如果操作失败(比如 image 不存在),也能在这里查看到原因。
总结一下这个过程:
用户通过 kubectl 创建 Deployment。
Deployment 创建 ReplicaSet。
ReplicaSet 创建 Pod
也可以看出,对象的命名方式是:子对象的名字 = 父对象名字 + 随机字符串或数字。
k8s支持两种创建资源的方式:
1.用 kubectl 命令直接创建,比如:
kubectl run nginx-deployment --image=nginx:1.7.9 --replicas=2
在命令行中通过参数指定资源的属性。
kubectl apply -f nginx.yml
nginx.yml 的内容为:
资源的属性写在配置文件中,文件格式为 YAML。
下面对这两种方式进行比较。
基于命令的方式:
简单直观快捷,上手快。
适合临时测试或实验。
基于配置文件的方式:
配置文件描述了 What,即应用最终要达到的状态。
配置文件提供了创建资源的模板,能够重复部署。
可以像管理代码一样管理部署。
适合正式的、跨环境的、规模化部署。
这种方式要求熟悉配置文件的语法,有一定难度。
后面我们都将采用配置文件的方式,大家需要尽快熟悉和掌握。
kubectl apply 不但能够创建 Kubernetes资源,也能对资源进行更新,非常方便。不过 Kubernets还提供了几个类似的命令,例如 kubectl create、kubectl replace、kubectl edit和 kubectl patch。
为避免造成不必要的困扰,我们会尽量只使用 kubectl apply,
此命令已经能够应对超过 90% 的场景,事半功倍。
既然要用 YAML 配置文件部署应用,现在就很有必要了解一下 Deployment 的配置格式,其他 Controller(比如 DaemonSet)非常类似。
① apiVersion 是当前配置格式的版本。
② kind 是要创建的资源类型,这里是 Deployment。
③ metadata 是该资源的元数据,name 是必需的元数据项。
④ spec 部分是该 Deployment 的规格说明。
⑤ replicas 指明副本数量,默认为 1。
⑥ template 定义 Pod 的模板,这是配置文件的重要部分。
⑦ metadata 定义 Pod 的元数据,至少要定义一个 label。label 的 key 和 value 可以任意指定。
⑧ spec 描述 Pod 的规格,此部分定义 Pod 中每一个容器的属性,name 和 image 是必需的。
此 nginx.yml 是一个最简单的 Deployment 配置文件,后面我们学习 Kubernetes 各项功能时会逐步丰富这个文件。
执行 kubectl apply -f nginx.yml:[root@ken ~]/# kubectl apply -f nginx.yml deployment.extensions/nginx-deployment created
查看nginx-deployment各种资源[root@ken ~]/# kubectl getdeployment NAME READY UP-TO-DATE AVAILABLE AGE httpd-ken 2/2 2 273m nginx-deployment 2/2 2 2107s [root@ken~]/# kubectl getreplicaset NAME DESIRED CURRENT READY AGE httpd-ken-5c949b96f 2 2 254m nginx-deployment-65998d8886 2 2 2111s [root@ken~]/# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES httpd-ken-5c949b96f-9cd52 1/1 Running 0 54m 10.244.1.3 host1
Deployment、ReplicaSet、Pod 都已经就绪。如果要删除这些资源,执行 kubectl delete deployment nginx-deployment 或者 kubectl delete -f nginx.yml (编写的nginx.yml文件不会被删除)。[root@ken ~]/# kubectl delete -f nginx.yml deployment.extensions"nginx-deployment" deleted
伸缩(Scale Up/Down)是指在线增加或减少 Pod的副本数。
Deployment nginx-deployment 初始是两个副本。[root@ken ~]/# kubectl apply -f nginx.yml [root@ken~]/# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-deployment-65998d8886-5b5rc 1/1 Running 0 84s 10.244.1.5 host1
k8s-node1 和 k8s-node2 上各跑了一个副本。现在修改 nginx.yml,将副本改成 5 个。
再次执行kubectl apply[root@ken ~]/# kubectl apply -f nginx.yml deployment.extensions/nginx-deployment configured
查看pod[root@ken ~]/# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-deployment-65998d8886-4hfgp 1/1 Running 0 3m 10.244.1.7 host1
三个新副本被创建并调度到 k8s-node1 和 k8s-node2上。
接下来修改配置文件,将副本数减少为 3 个,重新执行 kubectl apply:[root@ken ~]/# kubectl apply -f nginx.yml deployment.extensions/nginx-deployment configured [root@ken~]/# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-deployment-65998d8886-5b5rc 1/1 Running 0 7m6s 10.244.1.5 host1
可以看到两个副本被删除,最终保留了 3 个副本。
上面我们有 3 个 nginx副本分别运行在 k8s-node1和 k8s-node2上。现在模拟 k8s-node2故障,关闭该节点(poweroff)。
首先查看节点[root@ken ~]/# kubectl getnode NAME STATUS ROLES AGE VERSION host1 Ready
发现host2状态为NotReady
等待一段时间,Kubernetes 会检查到 k8s-node2 不可用,将 k8s-node2 上的 Pod 标记为 Terminating状态,并在 k8s-node1 上新创建两个 Pod,维持总副本数为 3。[root@ken ~]/# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-deployment-65998d8886-5b5rc 1/1 Running 0 16m 10.244.1.5 host1
当 k8s-node2 恢复后, Terminating的 Pod会被删除,不过已经运行的 Pod不会重新调度回 k8s-node2。[root@ken ~]/# kubectl getnode NAME STATUS ROLES AGE VERSION host1 Ready
删除 nginx-deployment:[root@ken ~]/# kubectl delete -f nginx.yml deployment.extensions"nginx-deployment" deleted
默认配置下,Scheduler 会将 Pod 调度到所有可用的 Node。不过有些情况我们希望将 Pod 部署到指定的 Node,比如将有大量磁盘 I/O 的 Pod 部署到配置了 SSD 的 Node;或者 Pod 需要 GPU,需要运行在配置了 GPU 的节点上。
Kubernetes 是通过 label 来实现这个功能的。
label 是 key-value 对,各种资源都可以设置 label,灵活添加各种自定义属性。比如执行如下命令标注 k8s-node1 是配置了 SSD 的节点。
第一步:定义标签
disk为自定义字符串[root@ken ~]/# kubectl label node host1 disk=ssd
第二步:查看标签[root@ken ~]/# kubectl get node --show-labels NAME STATUS ROLES AGE VERSION LABELS host1 Ready
disk=ssd 已经成功添加到 host1,除了 disk,Node 还有几个 Kubernetes 自己维护的 label。
第三步:配置nginx.yml
有了 disk 这个自定义 label,接下来就可以指定将 Pod 部署到 host1。编辑 nginx.yml:
在 Pod 模板的 spec里通过 nodeSelector指定将此 Pod部署到具有 label disktype=ssd的 Node上。
注意:1. nodeSelector需要与containers位置保持一致
2. S必须大写
第四步:部署
部署 Deployment[root@ken ~]/# kubectl apply -f nginx.yml deployment.extensions/nginx-deployment created
第五步:查看 Pod的运行节点[root@ken ~]/# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-deployment-5d8db4598d-2gdmz 0/1 ContainerCreating 0 102s
全部 3个副本都运行在 host1 上,符合我们的预期。
要删除 label disktype,执行如下命令:
kubectl label node k8s-node1 disktype-
不过此时 Pod 并不会重新部署,依然在 host1 上运行。[root@ken ~]/# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-deployment-5d8db4598d-2dbw9 1/1 Running 0 39s 10.244.1.12 host1
除非在 nginx.yml 中删除 nodeSelector设置,然后通过 kubectl apply重新部署。
不需要删除之前的deployment,直接部署即可
Kubernetes 自己会删除之前的 Pod 并调度和运行新的 Pod。[root@ken ~]/# kubectl apply -f nginx.yml [root@ken~]/# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-deployment-5d8db4598d-p87mj 0/1 Terminating 0 2m 10.244.1.13 host1