Deployment深入使用
- Deployment 资源清单文件编写技巧
- Deployment 使用案例:创建一个 web 站点
- Deployment 管理 pod:扩容、缩容、滚动更新、回滚
- 自定义滚动更新策略
- Deployment 资源清单详解
Deployment 资源清单文件编写技巧
查看 Deployment 资源对象由哪几部分组成
[root@k8smaster node]# kubectl explain deployment KIND: Deployment VERSION: apps/v1 DESCRIPTION: Deployment enables declarative updates for Pods and ReplicaSets. FIELDS: apiVersion <string> #该资源使用的 api 版本 kind <string> #创建的资源是什么? metadata <Object> #元数据,包括资源的名字和名称空间 spec <Object> #定义容器的 status <Object> #状态,不可以修改
查看 Deployment 下的 spec 字段
[root@xianchaomaster1 ~]# kubectl explain deployment.spec [root@k8smaster node]# kubectl explain deployment.spec KIND: Deployment VERSION: apps/v1 RESOURCE: spec <Object> DESCRIPTION: Specification of the desired behavior of the Deployment. DeploymentSpec is the specification of the desired behavior of the Deployment. FIELDS: minReadySeconds <integer> #Kubernetes 在等待设置的时间后才进行升级 如果没有设置该值,Kubernetes 会假设该容器启动起来后就提供服务了 paused <boolean> #暂停,当我们更新的时候创建 pod 先暂停,不是立即更新 progressDeadlineSeconds <integer> #k8s 在升级过程中有可能由于各种原因升级卡住(这个时候还没有明确的升级失败),比如在拉取被墙的镜像,权限不够等错误。那么这个时候就需要有个 deadline ,在 deadline 之内如果还卡着,那么就上报这个情况,这个时候这个 Deployment 状态就被标记为 False,并且注明原因。但是它并不会阻止 Deployment 继续进行卡住后面的操作。完全由用户进行控制。 replicas <integer> #副本数 revisionHistoryLimit <integer> #保留的历史版本,默认是 10 selector <Object> -required- #标签选择器,选择它关联的 pod strategy <Object> #更新策略 template <Object> -required- #定义的 pod 模板
查看 Deployment 下的 spec.strategy 字段
[root@k8smaster node]# kubectl explain deploy.spec.strategy KIND: Deployment VERSION: apps/v1 RESOURCE: strategy <Object> DESCRIPTION: The deployment strategy to use to replace existing pods with new ones. DeploymentStrategy describes how to replace existing pods with new ones. FIELDS: rollingUpdate <Object> #支持两种更新,Recreate 和 RollingUpdate #Recreate 是重建式更新,删除一个更新一个 #RollingUpdate 滚动更新,定义滚动更新方式,也就是 pod 能多几个,少几个 type <string> #查看 Deployment 下的 spec.strategy.rollingUpdate 字段 [root@k8smaster node]# kubectl explain deploy.spec.strategy.rollingUpdate KIND: Deployment VERSION: apps/v1 RESOURCE: rollingUpdate <Object> DESCRIPTION: Rolling update config params. Present only if DeploymentStrategyType = RollingUpdate. Spec to control the desired behavior of rolling update. FIELDS: maxSurge <string> #我们更新的过程当中最多允许超出的指定的目标副本数有几个,它有两种取值方式,第一种直接给定数量,第二种根据百分比,百分比表示原本是 5 个,最多可以超出 20%,那就允许多一个,最多可以超过 40%,那就允许多两个. maxUnavailable <string> #最多允许几个不可用 假设有 5 个副本,最多一个不可用,就表示最少有 4 个可用
查看 Deployment 下的 spec.template 字段,template 为定义 Pod 的模板,Deployment 通过模板创建 Pod
[root@k8smaster node]# kubectl explain deploy.spec.template KIND: Deployment VERSION: apps/v1 RESOURCE: template <Object> DESCRIPTION: Template describes the pods that will be created. PodTemplateSpec describes the data a pod should have when created from a template FIELDS: metadata <Object> #定义模板的名字 spec <Object> deployment.spec.template 为 Pod 定义的模板,和 Pod 定义不太一样,template 中不包含 apiVersion 和 Kind 属性,要求必须有 metadata。deployment.spec.template.spec 为容器的属性信息,其他定义内容和 Pod 一致。
查看 Deployment 下的 spec.template.spec 字段
[root@k8smaster node]# kubectl explain deploy.spec.template.spec KIND: Deployment VERSION: apps/v1 RESOURCE: spec <Object> DESCRIPTION: Specification of the desired behavior of the pod. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status PodSpec is a description of a pod. FIELDS: activeDeadlineSeconds <integer> #activeDeadlineSeconds 表示 Pod 可以运行的最长时间,达到设置的该值后,Pod 会自动停止。 affinity <Object> #定义亲和性,跟直接创建 pod 时候定义亲和性类似 automountServiceAccountToken <boolean> #身份认证相关的 containers <[]Object> -required- #定义容器属性 dnsConfig <Object> #设置 Pod 的 DNS 和 host 对齐 dnsPolicy: None dnsConfig: nameservers: - 192.168.11.141 - 192.168.11.140 searches: - paopao.svc.cluster.local - my.dns.search.paopao dnsPolicy <string> # dnsPolicy 决定 Pod 内预设的 DNS 配置策略 None 无任何策略:使用自定义的策略 Default 默认:使用宿主机的 dns 配置,/etc/resolv.conf ClusterFirst 集群 DNS 优先,与 Default 相反,会预先使用 kube-dns (或 CoreDNS ) 的信息当预设置参数写入到该 Pod 内的 DNS 配置。 ClusterFirstWithHostNet 集群 DNS 优先,并伴随着使用宿主机网络:同时使用 hostNetwork 与 kube-dns 作为 Pod 预设 DNS 配置。 enableServiceLinks <boolean> ephemeralContainers <[]Object> #定义临时容器 临时容器与其他容器的不同之处在于,它们缺少对资源或执行的保证,并且永远不会自动重启,因此不适用于构建应用程序。临时容器使用与常规容器相同的 ContainerSpec 段进行描述,但许多字段是不相容且不允许的。 临时容器没有端口配置,因此像 ports,livenessProbe,readinessProbe 这样的字段是不允许的,Pod 资源分配是不可变的,因此 resources 配置是不允许的。 临时容器用途: 当由于容器崩溃或容器镜像不包含调试应用程序而导致 kubectl exec 无用时,临时容器对于交互式故障排查很有用。 hostAliases <[]Object> #在 pod 中增加域名解析的 和 containers 对齐 hostAliases: – ip: "10.1.1.1" hostnames: – "mc.local" – "rabbitmq.local" - ip: "10.1.2.3" hostnames: – "redis.local" – "mq.local" hostIPC <boolean> #使用主机 IPC hostNetwork <boolean> #是否使用宿主机的网络 hostPID <boolean> #可以设置容器里是否可以看到宿主机上的进程。True 可以 hostname <string> imagePullSecrets <[]Object> initContainers <[]Object> #定义初始化容器 nodeName <string> #定义 pod 调度到具体哪个节点上 nodeSelector <map[string]string> #定义节点选择器 overhead <map[string]string> #overhead 是 1.16 引入的字段,在没有引入 Overhead 之前,只要一个节点的资源可用量大于等于 Pod 的 requests 时,这个 Pod 就可以被调度到这个节点上。引入 Overhead 之后,只有节点的资源可用量大于等于 Overhead 加上 requests 的和时才能被调度上来。 preemptionPolicy <string> priority <integer> priorityClassName <string> readinessGates <[]Object> restartPolicy <string> #Pod 重启策略 runtimeClassName <string> schedulerName <string> securityContext <Object> #是否开启特权模式 serviceAccount <string> serviceAccountName <string> shareProcessNamespace <boolean> subdomain <string> terminationGracePeriodSeconds <integer> #在真正删除容器之前,K8S 会先发终止信号(kill -15 {pid})给容器,默认 30s tolerations <[]Object> #定义容忍度 topologySpreadConstraints <[]Object> volumes <[]Object> #挂载存储卷
Deployment 使用案例:创建一个 web 站点
deployment 是一个三级结构,deployment 管理 replicaset,replicaset 管理 pod, 用 deployment 创建一个 pod #把 myapp-blue-v1.tar.gz 和 myapp-blue-v2.tar.gz 上传到 node1 和 node2 上, [root@k8snode ~]# docker load -i myapp-blue-v1.tar.gz [root@k8snode2 ~]# docker load -i myapp-blue-v1.tar.gz [root@k8snode ~]# docker load -i myapp-blue-v2.tar.gz [root@k8snode2 ~]# docker load -i myapp-blue-v2.tar.gz [root@xianchaomaster1 ~]# vim deploy-demo.yaml apiVersion: apps/v1 kind: Deployment metadata: name: myapp-v1 spec: replicas: 2 selector: matchLabels: app: myapp version: v1 template: metadata: name: test labels: app: myapp version: v1 spec: containers: - name: myapp image: janakiramm/myapp:v1 imagePullPolicy: IfNotPresent ports: - containerPort: 80 livenessProbe: httpGet: port: 80 readinessProbe: httpGet: port: 80 #不加ip默认是对主机ip进行httpget存活验证 [root@k8smaster node]# kubectl apply -f deploy-demo.yaml deployment.apps/myapp-v1 created #kubectl apply:表示声明式的定义,既可以创建资源,也可以动态更新资源 [root@k8smaster node]# kubectl get deploy NAME READY UP-TO-DATE AVAILABLE AGE myapp-v1 2/2 2 2 41s #创建的控制器名字是 myapp-v1 1.NAME :列出名称空间中 deployment 的名称。 2.READY:显示 deployment 有多少副本数。它遵循 ready/desired 的模式。 3.UP-TO-DATE: 显示已更新到所需状态的副本数。 4.AVAILABLE: 显示你的可以使用多少个应用程序副本。 5.AGE :显示应用程序已运行的时间。 [root@k8smaster node]# kubectl get rs NAME DESIRED CURRENT READY AGE myapp-v1-8ff97699c 2 2 2 72s #创建 deploy 的时候也会创建一个 rs(replicaset),8ff97699c 这个随机数字是我们引用pod 的模板 template 的名字的 hash 值 1.NAME: 列出名称空间中 ReplicaSet 资源 2.DESIRED:显示应用程序的所需副本数,这些副本数是在创建时定义的。这是所需的状态。 3.CURRENT: 显示当前正在运行多少个副本。 4.READY: 显示你的用户可以使用多少个应用程序副本。 5.AGE :显示应用程序已运行的时间。 #请注意,ReplicaSet 的名称始终设置为[DEPLOYMENT-NAME]-[RANDOM-STRING]。RANDOM-STRING 是随机生成的 [root@k8smaster node]# kubectl get pods NAME READY STATUS RESTARTS AGE myapp-v1-8ff97699c-42wts 1/1 Running 0 2m20s myapp-v1-8ff97699c-vvld2 1/1 Running 0 2m20s [root@k8smaster node]# kubectl get pods -o wide | grep myapp myapp-v1-8ff97699c-42wts 1/1 Running 0 2m35s 10.244.2.31 k8snode <none> myapp-v1-8ff97699c-vvld2 1/1 Running 0 2m35s 10.244.1.21 k8snode2 <none> #请求刚才创建的 pod 资源 [root@k8smaster node]# curl 10.244.2.31 background-color: blue; [root@k8smaster node]# curl 10.244.1.21 background-color: blue; #资源清单文件详细解读 apiVersion: apps/v1 #deployment 对应的 api 版本 kind: Deployment #创建的资源是 deployment metadata: name: myapp-v1 #deployment 的名字 spec: replicas: 2 #deployment 管理的 pod 副本数 selector: #标签选择器 matchLabels: # matchLabels 下定义的标签需要跟 template.metadata.labels 定义的标签一致 app: myapp version: v1 template: metadata: labels: app: myapp version: v1 spec: #定义容器的属性 containers: - name: myapp image: janakiramm/myapp:v1 #容器使用的镜像 imagePullPolicy: IfNotPresent #镜像拉取策略 ports: - containerPort: 80 #容器里的应用的端口
Deployment 管理 pod:扩容、缩容、滚动更新、回滚
#通过 deployment 管理应用,实现扩容,把副本数变成 3 [root@k8smaster node]# vim deploy-demo.yaml 直接修改 replicas 数量,如下,变成 3 spec: replicas: 3 修改之后保存退出,执行 [root@k8smaster node]# kubectl apply -f deploy-demo.yaml 注意:apply 不同于 create,apply 可以执行多次;create 执行一次,再执行就会报错复。 [root@k8smaster node]# kubectl get pods 显示如下: [root@k8smaster node]# kubectl get pods NAME READY STATUS RESTARTS AGE myapp-v1-646f8f7485-5xbpc 1/1 Running 0 16h myapp-v1-646f8f7485-jksp9 1/1 Running 0 16h myapp-v1-646f8f7485-ntbkx 1/1 Running 0 4s #上面可以看到 pod 副本数变成了 3 个 #查看 myapp-v1 这个控制器的详细信息 [root@k8smaster node]# kubectl describe deploy myapp-v1 Name: myapp-v1 Namespace: default CreationTimestamp: Mon, 11 Jul 2022 04:36:48 -0700 Labels: <none> Annotations: deployment.kubernetes.io/revision: 2 Selector: app=myapp,version=v1 Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable StrategyType: RollingUpdate MinReadySeconds: 0 RollingUpdateStrategy: 25% max unavailable, 25% max surge Pod Template: Labels: app=myapp version=v1 Containers: myapp: Image: janakiramm/myapp:v1 Port: 80/TCP Host Port: 0/TCP Liveness: http-get http://:80/ delay=0s timeout=1s period=10s #success=1 #failure=3 Environment: <none> Mounts: <none> Volumes: <none> Conditions: Type Status Reason ---- ------ ------ Progressing True NewReplicaSetAvailable Available True MinimumReplicasAvailable OldReplicaSets: <none> NewReplicaSet: myapp-v1-646f8f7485 (3/3 replicas created) Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ScalingReplicaSet 16h deployment-controller Scaled up replica set myapp-v1-8ff97699c to 2 Normal ScalingReplicaSet 16h deployment-controller Scaled up replica set myapp-v1-646f8f7485 to 1 Normal ScalingReplicaSet 16h deployment-controller Scaled down replica set myapp-v1-8ff97699c to 1 Normal ScalingReplicaSet 16h deployment-controller Scaled up replica set myapp-v1-646f8f7485 to 2 Normal ScalingReplicaSet 16h deployment-controller Scaled down replica set myapp-v1-8ff97699c to 0 Normal ScalingReplicaSet 26s deployment-controller Scaled up replica set myapp-v1-646f8f7485 to 3 #通过 deployment 管理应用,实现缩容,把副本数变成 2 [root@k8smaster node]# vim deploy-demo.yaml 直接修改 replicas 数量,如下,变成 2 spec: replicas: 2 修改之后保存退出,执行 [root@k8smaster node]# kubectl apply -f deploy-demo.yaml [root@k8smaster node]# kubectl get pods NAME READY STATUS RESTARTS AGE myapp-v1-646f8f7485-5xbpc 1/1 Running 0 16h myapp-v1-646f8f7485-jksp9 1/1 Running 0 16h #通过 deployment 管理应用,实现滚动更新 在一个终端窗口执行如下 [root@k8smaster node]# kubectl get pods -l app=myapp -w NAME READY STATUS RESTARTS AGE myapp-v1-646f8f7485-5xbpc 1/1 Running 0 16h myapp-v1-646f8f7485-jksp9 1/1 Running 0 16h 打开一个新的终端窗口更改镜像版本,按如下操作 [root@k8smaster node]# vim deploy-demo.yaml 把 image: janakiramm/myapp:v1 变成 image: janakiramm/myapp:v2 保存退出,执行 [root@k8smaster node]# kubectl apply -f deploy-demo.yaml 再回到刚才执行监测 kubectl get pods -l app=myapp -w 的那个窗口,可以看到信息如下 NAME READY STATUS RESTARTS AGE myapp-pod 1/1 Running 8 43h myapp-v1-646f8f7485-5xbpc 1/1 Running 0 16h myapp-v1-646f8f7485-jksp9 1/1 Running 0 16h myapp-v1-68b9dcdb96-hwgkl 0/1 Pending 0 0s myapp-v1-68b9dcdb96-hwgkl 0/1 Pending 0 0s myapp-v1-68b9dcdb96-hwgkl 0/1 ContainerCreating 0 0s myapp-v1-68b9dcdb96-hwgkl 1/1 Running 0 2s myapp-v1-646f8f7485-5xbpc 1/1 Terminating 0 16h myapp-v1-68b9dcdb96-lj5xl 0/1 Pending 0 0s myapp-v1-68b9dcdb96-lj5xl 0/1 Pending 0 0s myapp-v1-68b9dcdb96-lj5xl 0/1 ContainerCreating 0 0s myapp-v1-646f8f7485-5xbpc 0/1 Terminating 0 16h myapp-v1-68b9dcdb96-lj5xl 1/1 Running 0 1s myapp-v1-646f8f7485-jksp9 1/1 Terminating 0 16h myapp-v1-646f8f7485-jksp9 0/1 Terminating 0 16h myapp-v1-646f8f7485-jksp9 0/1 Terminating 0 16h myapp-v1-646f8f7485-jksp9 0/1 Terminating 0 16h myapp-v1-646f8f7485-5xbpc 0/1 Terminating 0 16h myapp-v1-646f8f7485-5xbpc 0/1 Terminating 0 16h pending 表示正在进行调度,ContainerCreating 表示正在创建一个 pod,running 表示运行一个 pod,running 起来一个 pod 之后再 Terminating(停掉)一个 pod,以此类推,直到所有 pod 完成滚动升级,它是自动的,不用手动去删除! 在另外一个窗口执行 [root@k8smaster node]# kubectl get rs NAME DESIRED CURRENT READY AGE myapp-v1-646f8f7485 0 0 0 16h myapp-v1-68b9dcdb96 2 2 2 52s #上面可以看到 rs 有两个,上面那个是升级之前的,已经被停掉,但是可以随时回滚 #查看 myapp-v1 这个控制器的历史版本 [root@k8smaster node]# kubectl rollout history deployment myapp-v1 deployment.apps/myapp-v1 REVISION CHANGE-CAUSE 1 <none> 2 <none> 3 <none> #回滚到指定版本 [root@k8smaster node]# kubectl rollout undo deployment myapp-v1 --to-revision=1 deployment.apps/myapp-v1 rolled back [root@k8smaster node]# kubectl rollout history deployment myapp-v1 deployment.apps/myapp-v1 REVISION CHANGE-CAUSE 2 <none> 3 <none> 4 <none>
自定义滚动更新策略
maxSurge 和 maxUnavailable 用来控制滚动更新的更新策略
取值范围
数值
1.maxUnavailable: [0, 副本数]
2.maxSurge: [0, 副本数] 注意:两者不能同时为 0。
比例
1.maxUnavailable: [0%, 100%] 向下取整,比如 10 个副本,5%的话==0.5 个,但计算按照 0 个。
2.maxSurge: [0%, 100%] 向上取整,比如 10 个副本,5%的话==0.5 个,但计算按照 1 个。 注意:两者不能同时为 0。
建议配置
1.maxUnavailable == 0
2.maxSurge == 1
这是我们生产环境提供给用户的默认配置。即“一上一下,先上后下”最平滑原则:
一个新版本 pod ready(结合 readiness)后,才销毁旧版本 pod。此配置适用场景是平滑更新、保证服务平稳,但也有缺点,就是太慢了。
总结:
maxUnavailable:和期望的副本数比,不可用副本数最大比例(或最大值),这个值越小,越能保证服务稳定,更新越平滑;
maxSurge:和期望的副本数比,超过期望副本数最大比例(或最大值),这个值调的越大,副本更新速度越快。
自定义策略: 修改更新策略:maxUnavailable=1,maxSurge=1 apiVersion: apps/v1 kind: Deployment metadata: name: myapp-v1 spec: replicas: 2 selector: matchLabels: app: myapp version: v1 strategy: #从这里开始就是新的策略 同时更新一下镜像版本 不然不会更新 rollingUpdate: maxSurge: 1 maxUnavailable: 1 maxunava默认就行了,防止有两个pod才能提供服务的时候挂一个出问题 查看 myapp-v1 这个控制器的详细信息 [root@k8smaster node]# kubectl describe deployment myapp-v1 Name: myapp-v1 Namespace: default CreationTimestamp: Mon, 11 Jul 2022 04:36:48 -0700 Labels: <none> Annotations: deployment.kubernetes.io/revision: 5 Selector: app=myapp,version=v1 Replicas: 2 desired | 2 updated | 2 total | 2 available | 0 unavailable StrategyType: RollingUpdate MinReadySeconds: 0 RollingUpdateStrategy: 1 max unavailable, 1 max surge 上面可以看到 RollingUpdateStrategy: 1 max unavailable, 1 max surge 这个 rollingUpdate 更新策略变成了刚才设定的,因为我们设定的 pod 副本数是 2,1 和 1 表示最少不能少于 1 个 pod,最多不能超过 3 个 pod 这个就是通过控制 RollingUpdateStrategy 这个字段来设置滚动更新策略的.
Deployment 资源清单详解
apiVersion: apps/v1 kind: Deployment metadata: name: tomcat-tpp namespace: ms spec: replicas: 1 selector: matchLabels: project: ms app: portal template: metadata: labels: project: ms app: portal spec: containers: - name: portal image: tomcat imagePullPolicy: Always ports: - protocol: TCP containerPort: 8080 resources: #资源配额 如果超过会被重启 根据项目实际修改 limits: #资源限制,最多可用的 cpu 和内存 cpu: 1 memory: 1Gi requests: #最少需要多少资源才可以运行 Pod cpu: 0.5 memory: 1Gi readinessProbe: tcpSocket: port: 8080 initialDelaySeconds: 60 periodSeconds: 10 livenessProbe: tcpSocket: port: 8080 initialDelaySeconds: 60 periodSeconds: 10 livenessProbe: #存活性探测 #用于判断容器是否存活,即 Pod 是否为 running 状态,如果 LivenessProbe 探针探测到容器不健康,则kubelet 将 kill 掉容器,并根据容器的重启策略是否重启。如果一个容器不包含 LivenessProbe 探针,则 Kubelet 认为容器的 LivenessProbe 探针的返回值永远成功。 tcpSocket: port: 8080 #检测 8080 端口是否存在 initialDelaySeconds: 60 #Pod 启动 60s 执行第一次检查 periodSeconds: 10 #第一次检查后每隔 10s 检查一次 readinessProbe: #就绪性探测 有时候应用程序可能暂时无法接受请求,比如 Pod 已经 Running 了,但是容器内应用程序尚未启动成功,在这种情况下,如果没有 ReadinessProbe,则 Kubernetes 认为它可以处理请求了,然而此时,我们知道程序还没启动成功是不能接收用户请求的,所以不希望 kubernetes 把请求调度给它,则使用ReadinessProbe 探针。 ReadinessProbe 和 livenessProbe 可以使用相同探测方式,只是对 Pod 的处置方式不同,ReadinessProbe 是将 Pod IP:Port 从对应的 EndPoint 列表中删除,而 livenessProbe 则 Kill 容器并根据 Pod 的重启策略来决定作出对应的措施。 ReadinessProbe 探针探测容器是否已准备就绪,如果未准备就绪则 kubernetes 不会将流量转发给此Pod。 tcpSocket: port: 8080 initialDelaySeconds: 60 periodSeconds: 10 #在 Pod 运行过程中,K8S 仍然会每隔 10s 检测 8080 端口