使用Kubernetes部署第一个应用
目录
前提条件
启动集群
部署 nginx 应用
创建 YAML 文件
应用 YAML 文件
查看部署结果
理解Pods
相关命令
公布应用程序
问题背景
Kubernetes Service(服务)概述
服务和标签
为Deployment 创建一个 Service
伸缩应用程序
Scaling(伸缩)应用程序
将Deployment扩容到4个副本
将Deployment缩容到2个副本
滚动更新应用
滚动更新概述
滚动更新步骤
滚动更新Deployment
删除部署资源
相关命令
删除部署资源
前提条件
-
完成 Kubernetes 集群的安装,可参考Kubernetes集群搭建
-
了解Kubernetes常用命令,可参考Kubernetes常用命令
启动集群
启动ikuai,启动三个虚拟机,确保Kubernetes集群正常可用。
[root@k8s-master01 ~]# kubectl get node NAME STATUS ROLES AGE VERSION k8s-master01 Ready control-plane 7h52m v1.31.1 k8s-node01 Ready <none> 7h24m v1.31.1 k8s-node02 Ready <none> 7h22m v1.31.1
部署 nginx 应用
在 k8s 上进行部署前,首先需要了解一个基本概念 Deployment
Deployment 译名为 部署 。在k8s中,通过发布 Deployment,可以创建应用程序 (docker image) 的实例 (docker container),这个实例会被包含在称为 Pod 的概念中,Pod 是 k8s 中最小可管理单元。
在 k8s 集群中发布 Deployment 后,Deployment 将指示 k8s 如何创建和更新应用程序的实例,master 节点将应用程序实例调度到集群中的具体的节点上。
创建应用程序实例后,Kubernetes Deployment Controller 会持续监控这些实例。如果运行实例的 worker 节点关机或被删除,则 Kubernetes Deployment Controller 将在群集中资源最优的另一个 worker 节点上重新创建一个新的实例。这提供了一种自我修复机制来解决机器故障或维护问题。
创建 YAML 文件
创建nginx-deployment.yaml文件
# 创建专门的目录,方便管理yaml文件 [root@k8s-master01 ~]# mkdir 1 [root@k8s-master01 ~]# cd 1 # 创建nginx-deployment.yaml [root@k8s-master01 1]# vi nginx-deployment.yaml
内容如下:
apiVersion: apps/v1 #与k8s集群版本有关,使用 kubectl api-versions 即可查看当前集群支持的版本
kind: Deployment #该配置的类型,使用的是 Deployment
metadata: #译名为元数据,即 Deployment 的一些基本属性和信息
name: nginx-deployment #Deployment 的名称
labels: #标签,可以灵活定位一个或多个资源,其中key和value均可自定义,可以定义多组,目前不需要理解
app: nginx #为该Deployment设置key为app,value为nginx的标签
spec: #这是关于该Deployment的描述,可以理解为你期待该Deployment在k8s中如何使用
replicas: 1 #使用该Deployment创建一个应用程序实例
selector: #标签选择器,与上面的标签共同作用,目前不需要理解
matchLabels: #选择包含标签app:nginx的资源
app: nginx
template: #这是选择或创建的Pod的模板
metadata: #Pod的元数据
labels: #Pod的标签,上面的selector即选择包含标签app:nginx的Pod
app: nginx
spec: #期望Pod实现的功能(即在pod中部署)
containers: #生成container,与docker中的container是同一种
- name: nginx #container的名称
image: nginx:alpine #使用镜像nginx:alpine创建container,该container默认80端口可访问
应用 YAML 文件
应用yaml文件创建deployment
[root@k8s-master01 1]# kubectl apply -f nginx-deployment.yaml
查看部署结果
[root@k8s-master01 1]# kubectl get deployments NAME READY UP-TO-DATE AVAILABLE AGE nginx-deployment 1/1 1 1 10s [root@k8s-master01 1]# kubectl get pods NAME READY STATUS RESTARTS AGE nginx-deployment-9c65654f4-xj7j2 1/1 Running 0 47s
分别查看到一个名为 nginx-deployment 的 Deployment 和一个名为 nginx-deployment-xxxxxxx 的 Pod,Pod的状态是Running状态。
至此已经成功在k8s上部署了一个nginx应用程序。
理解Pods
Pods 是 Kubernetes 中最小的可部署和可管理的单元。部署应用,其实就是部署Pod。
Pod 是一个k8s中一个抽象的概念,用于存放一组 container(可包含一个或多个 container 容器,即图上正方体),以及这些 container (容器)的一些共享资源。这些资源包括:
-
共享存储,称为卷(Volumes),即图上紫色圆柱
-
网络,每个 Pod(容器组)在集群中有个唯一的 IP,pod(容器组)中的 container(容器)共享该IP地址
-
container(容器)的基本信息,例如容器的镜像版本,对外暴露的端口等
Pod中的容器共享 IP 地址和端口空间(同一 Pod 中的不同 container 使用的端口不能相互冲突),始终位于同一位置并共同调度,并在同一节点上的共享上下文中运行。(同一个Pod内的容器可以使用 localhost + 端口号互相访问)。
Pod一般存在于Node节点中,一个Node可以有多个Pod,下图显示一个 Node节点上含有4个 Pod。
相关命令
-
kubectl get - 显示资源列表
# kubectl get 资源类型 # 获取类型为Deployment的资源列表 kubectl get deployments # 获取类型为Pod的资源列表 kubectl get pods # 获取类型为Node的资源列表 kubectl get nodes
操作过程
[root@k8s-master01 1]# kubectl get deployments NAME READY UP-TO-DATE AVAILABLE AGE nginx-deployment 1/1 1 1 29m [root@k8s-master01 1]# kubectl get pods NAME READY STATUS RESTARTS AGE nginx-deployment-9c65654f4-xj7j2 1/1 Running 0 4m47s [root@k8s-master01 1]# kubectl get nodes NAME STATUS ROLES AGE VERSION k8s-master01 Ready control-plane 25d v1.31.1 k8s-node01 Ready <none> 25d v1.31.1 k8s-node02 Ready <none> 25d v1.31.1
名称空间
在命令后增加
-A
或--all-namespaces
可查看所有 名称空间中 的对象,使用参数-n
可查看指定名称空间的对象,例如# 查看所有名称空间的 Deployment kubectl get deployments -A kubectl get deployments --all-namespaces # 查看 kube-system 名称空间的 Deployment kubectl get deployments -n kube-system
并非所有对象都在名称空间里
操作过程
[root@k8s-master01 1]# kubectl get deployments -A NAMESPACE NAME READY UP-TO-DATE AVAILABLE AGE default nginx-deployment 1/1 1 1 31m kube-system calico-kube-controllers 1/1 1 1 25d kube-system calico-typha 1/1 1 1 25d kube-system coredns 2/2 2 2 25d myns1 my-dep 3/3 3 3 2d5h [root@k8s-master01 1]# kubectl get deployments --all-namespaces NAMESPACE NAME READY UP-TO-DATE AVAILABLE AGE default nginx-deployment 1/1 1 1 32m kube-system calico-kube-controllers 1/1 1 1 25d kube-system calico-typha 1/1 1 1 25d kube-system coredns 2/2 2 2 25d myns1 my-dep 3/3 3 3 2d5h [root@k8s-master01 1]# kubectl get deployments -n kube-system NAME READY UP-TO-DATE AVAILABLE AGE calico-kube-controllers 1/1 1 1 25d calico-typha 1/1 1 1 25d coredns 2/2 2 2 25d
-
kubectl describe - 显示有关资源的详细信息
# kubectl describe 资源类型 资源名称 #查看名称为nginx的Deployment的信息 kubectl describe deployment nginx #查看名称为nginx-XXXXXX的Pod的信息,可以查看到pod ip等信息 kubectl describe pod nginx-XXXXXX
操作过程
[root@k8s-master01 1]# kubectl describe deployment nginx-deployment Name: nginx-deployment Namespace: default CreationTimestamp: Wed, 09 Oct 2024 23:39:57 +0800 Labels: app=nginx Annotations: deployment.kubernetes.io/revision: 2 Selector: app=nginx Replicas: 1 desired | 1 updated | 1 total | 1 available | 0 unavailable StrategyType: RollingUpdate MinReadySeconds: 0 RollingUpdateStrategy: 25% max unavailable, 25% max surge Pod Template: Labels: app=nginx Containers: nginx: Image: nginx:alpine Port: <none> Host Port: <none> Environment: <none> Mounts: <none> Volumes: <none> Node-Selectors: <none> Tolerations: <none> Conditions: Type Status Reason ---- ------ ------ Available True MinimumReplicasAvailable Progressing True NewReplicaSetAvailable OldReplicaSets: nginx-deployment-75b5b48df5 (0/0 replicas created) NewReplicaSet: nginx-deployment-9c65654f4 (1/1 replicas created) Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ScalingReplicaSet 35m deployment-controller Scaled up replica set nginx-deployment-75b5b48df5 to 1 Normal ScalingReplicaSet 10m deployment-controller Scaled up replica set nginx-deployment-9c65654f4 to 1 Normal ScalingReplicaSet 10m deployment-controller Scaled down replica set nginx-deployment-75b5b48df5 to 0 from 1 [root@k8s-master01 1]# [root@k8s-master01 1]# kubectl describe pod nginx-deployment-9c65654f4-xj7j2 Name: nginx-deployment-9c65654f4-xj7j2 Namespace: default Priority: 0 Service Account: default Node: k8s-node01/192.168.204.102 Start Time: Thu, 10 Oct 2024 00:04:49 +0800 Labels: app=nginx pod-template-hash=9c65654f4 Annotations: cni.projectcalico.org/containerID: ad5ba24cae9654b42af7b5581095ee1c3246bc77e64ea42d08200653f148ade6 cni.projectcalico.org/podIP: 10.244.85.197/32 cni.projectcalico.org/podIPs: 10.244.85.197/32 Status: Running IP: 10.244.85.197 IPs: IP: 10.244.85.197 Controlled By: ReplicaSet/nginx-deployment-9c65654f4 Containers: nginx: Container ID: docker://5aa9bed2c3ae7ed772d7dc04420d4d79951dbacdb758bc013aa3c03a710ca138 Image: nginx:alpine Image ID: docker-pullable://nginx@sha256:2140dad235c130ac861018a4e13a6bc8aea3a35f3a40e20c1b060d51a7efd250 Port: <none> Host Port: <none> State: Running Started: Thu, 10 Oct 2024 00:04:50 +0800 Ready: True Restart Count: 0 Environment: <none> Mounts: /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-8962w (ro) Conditions: Type Status PodReadyToStartContainers True Initialized True Ready True ContainersReady True PodScheduled True Volumes: kube-api-access-8962w: Type: Projected (a volume that contains injected data from multiple sources) TokenExpirationSeconds: 3607 ConfigMapName: kube-root-ca.crt ConfigMapOptional: <nil> DownwardAPI: true QoS Class: BestEffort Node-Selectors: <none> Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s node.kubernetes.io/unreachable:NoExecute op=Exists for 300s Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 8m40s default-scheduler Successfully assigned default/nginx-deployment-9c65654f4-xj7j2 to k8s-node01 Normal Pulled 8m39s kubelet Container image "nginx:alpine" already present on machine Normal Created 8m39s kubelet Created container nginx Normal Started 8m38s kubelet Started container nginx [root@k8s-master01 1]#
-
kubectl logs - 查看pod中的容器的打印日志(和命令docker logs 类似),方便定位pod的问题。
# kubectl logs Pod名称 # -f表示持续监听日志,按ctrl+c退出监听,可以curl pod的ip,再次查看日志,会多一条出访问日志 kubectl logs -f nginx-pod-XXXXXXX
操作过程
[root@k8s-master01 1]# kubectl logs nginx-deployment-9c65654f4-xj7j2 /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/ /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh 10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf 10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf /docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh /docker-entrypoint.sh: Configuration complete; ready for start up 2024/10/09 16:04:51 [notice] 1#1: using the "epoll" event method 2024/10/09 16:04:51 [notice] 1#1: nginx/1.27.2 2024/10/09 16:04:51 [notice] 1#1: built by gcc 13.2.1 20240309 (Alpine 13.2.1_git20240309) 2024/10/09 16:04:51 [notice] 1#1: OS: Linux 5.14.0-427.33.1.el9_4.x86_64 2024/10/09 16:04:51 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1073741816:1073741816 2024/10/09 16:04:51 [notice] 1#1: start worker processes 2024/10/09 16:04:51 [notice] 1#1: start worker process 30 2024/10/09 16:04:51 [notice] 1#1: start worker process 31 2024/10/09 16:04:51 [notice] 1#1: start worker process 32 2024/10/09 16:04:51 [notice] 1#1: start worker process 33
-
kubectl exec - 在pod中的容器环境内执行命令(和命令docker exec 类似)
# kubectl exec Pod名称 操作命令 # 进入名称为nginx-pod-xxxxxx的Pod中运行bash,注意需要镜像支持bash命令 kubectl exec -it nginx-pod-xxxxxx -- bash # 不进入Pod,在名称为nginx-pod-xxxxxx的Pod中运行命令 kubectl exec -it nginx-pod-xxxxxx -- command
操作
# 注意,执行bash命令,需要镜像支持bash命令,nginx:alpline不支持bash命令,如果需要验证,可以把镜像缓存支持bash命令的镜像,例如:nginx:1.27.2 [root@k8s-master01 1]# kubectl exec -it nginx-deployment-9c65654f4-xj7j2 -- bash root@nginx-deployment-9c65654f4-xj7j2:/# ls bin dev home lib64 mnt proc run srv tmp var boot etc lib media opt root sbin sys usr root@nginx-deployment-9c65654f4-xj7j2:/# exit exit [root@k8s-master01 1]# [root@k8s-master01 1]# kubectl exec -it nginx-deployment-9c65654f4-xj7j2 -- date Wed Oct 9 16:23:16 UTC 2024 [root@k8s-master01 1]# kubectl exec -it nginx-deployment-9c65654f4-xj7j2 -- ls /usr/share/nginx/html 50x.html index.html
公布应用程序
问题背景
Deployment部署应用程序只能在集群内部访问,集群外部无法访问。
通过kubectl describe pod-name命令查看pod ip
[root@k8s-master01 ~]# kubectl describe pod nginx-deployment-9c65654f4-xj7j2 ... IP: 10.244.85.197 ...
这里查看的pod ip为:10.244.85.197
在集群任意一台机器命令访问pod ip:端口号,都可以访问到pod nginx服务。
[root@k8s-master01 ~]# curl 10.244.85.200:80 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> html { color-scheme: light dark; } body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html>
但在集群外部访问,例如:使用Windows的浏览器访问,却访问不到。
通过Deployment部署的应用程序,只能集群内部机器使用Pod IP进行访问,集群外部不能访问,如果Pod所在机器出现故障,Deployment重启Pod,Pod IP会变化。为了解决Pod IP可能变化同时还要让外部能访问的问题,这时就需要使用Kubernetes Service来公开应用程序。
Kubernetes Service(服务)概述
事实上,Pod(容器组)有自己的 生命周期。当 node(节点)故障时,节点上运行的 Pod(容器组)也会消失。然后,Deployment可以通过创建新的 Pod(容器组)来动态地将群集调整回原来的状态,以使应用程序保持运行。
举个例子,假设有一个后端程序,具有 3 个运行时副本。这 3 个副本是可以替换的(无状态应用),即使 Pod消失并被重新创建,或者副本数由 3 增加到 5,前端系统也无需关注后端副本的变化。由于 Kubernetes 集群中每个 Pod都有一个唯一的 IP 地址,我们需要一种机制,为前端系统屏蔽后端系统的 Pod在销毁、创建过程中所带来的 IP 地址的变化。
Kubernetes 中的 Service(服务) 提供了这样的一个抽象层,它选择具备某些特征的 Pod并为它们定义一个访问方式。Service使 Pod之间的相互依赖解耦(原本从一个 Pod 中访问另外一个 Pod,需要知道对方的 IP 地址)。一个 Service选定哪些 Pod通常由 LabelSelector(标签选择器) 来决定。
在创建Service的时候,通过设置配置文件中的 spec.type 字段的值,可以以不同方式向外部暴露应用程序:
-
ClusterIP(默认)
在群集中的内部IP上公布服务,这种方式的 Service(服务)只在集群内部可以访问到。
-
NodePort
使用 NAT 在集群中每个的同一端口上公布服务。这种方式下,可以通过访问集群中任意节点+端口号的方式访问服务
<NodeIP>:<NodePort>
。此时 ClusterIP 的访问方式仍然可用。 -
LoadBalancer
在云环境中(需要云供应商可以支持)创建一个集群外部的负载均衡器,并为使用该负载均衡器的 IP 地址作为服务的访问地址。此时 ClusterIP 和 NodePort 的访问方式仍然可用。
Service是一个抽象层,它通过 LabelSelector 选择了一组 Pod,把这些 Pod 的指定端口公布到到集群外部,并支持负载均衡和服务发现。
-
公布 Pod 的端口以使其可访问
-
在多个 Pod 间实现负载均衡
-
使用 Label 和 LabelSelector
服务和标签
图中有两个服务Service A(黄色虚线)和Service B(蓝色虚线)
- Service A 将请求转发到 IP 为 10.10.10.1 的Pod上
- Service B 将请求转发到 IP 为 10.10.10.2、10.10.10.3、10.10.10.4 的Pod上
Service 将外部请求路由到一组 Pod 中,它提供了一个抽象层,使得 Kubernetes 可以在不影响服务调用者的情况下,动态调度容器组(在容器组失效后重新创建容器组,增加或者减少同一个 Deployment 对应容器组的数量等)。
Service使用 Labels、LabelSelector(标签和选择器) (opens new window)匹配一组 Pod。Labels(标签)是附加到 Kubernetes 对象的键/值对,其用途有多种:
-
将 Kubernetes 对象(Node、Deployment、Pod、Service等)指派用于开发环境、测试环境或生产环境
-
嵌入版本标签,使用标签区别不同应用软件版本
-
使用标签对 Kubernetes 对象进行分类
下图体现了 Labels(标签)和 LabelSelector(标签选择器)之间的关联关系
-
Deployment B 含有 LabelSelector 为 app=B 通过此方式声明含有 app=B 标签的 Pod 与之关联
-
通过 Deployment B 创建的 Pod 包含标签为 app=B
-
Service B 通过标签选择器 app=B 选择可以路由的 Pod
Labels(标签)可以在创建 Kubernetes 对象时附加上去,也可以在创建之后再附加上去。任何时候都可以修改一个 Kubernetes 对象的 Labels(标签)
为Deployment 创建一个 Service
创建nginx的Deployment中定义了Labels,如下:
metadata: #译名为元数据,即Deployment的一些基本属性和信息 name: nginx-deployment #Deployment的名称 labels: #标签,可以灵活定位一个或多个资源,其中key和value均可自定义,可以定义多组 app: nginx #为该Deployment设置key为app,value为nginx的标签
此前的 nginx-deployment.yaml
已经有labels设置,所以不需要改动。
创建文件 nginx-service.yaml
[root@k8s-master01 1]# vi nginx-service.yaml
文件内容如下:
apiVersion: v1
kind: Service
metadata:
name: nginx-service #Service 的名称
labels: #Service 自己的标签
app: nginx #为该 Service 设置 key 为 app,value 为 nginx 的标签
spec: #这是关于该 Service 的定义,描述了 Service 如何选择 Pod,如何被访问
selector: #标签选择器
app: nginx #选择包含标签 app:nginx 的 Pod
ports:
- name: nginx-port #端口的名字
protocol: TCP #协议类型 TCP/UDP
port: 80 #集群内的其他容器组可通过 80 端口访问 Service
nodePort: 32600 #通过任意节点的 32600 端口访问 Service
targetPort: 80 #将请求转发到匹配 Pod 的 80 端口
type: NodePort #Serive的类型,ClusterIP/NodePort/LoaderBalancer
应用nginx-service.yaml
应用nginx-service.yaml创建service
[root@k8s-master01 1]# kubectl apply -f nginx-service.yaml
查看service
查看到名称为 nginx-service 的服务,类型为NodePort,端口映射关系为pod的80端口映射到主机的32600端口。
[root@k8s-master01 1]# kubectl get services -o wide NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 25d <none> nginx-service NodePort 10.12.211.39 <none> 80:32600/TCP 28s app=nginx
访问服务
访问集群任意机器IP:主机端口
命令访问测试
curl <任意节点的 IP>:32600
- 主机端口用上一步查看到映射的主机端口,需要根据实际情况修改
- 如果集群在云上需要在云服务商的安全组开放对应主机端口的访问
操作过程
# master01机器 [root@k8s-master01 1]# curl localhost:32600 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> html { color-scheme: light dark; } body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html> # node01机器 [root@k8s-node01 ~]# curl localhost:32600 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> html { color-scheme: light dark; } body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html> # node02机器 [root@k8s-node02 ~]# curl localhost:32600 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> html { color-scheme: light dark; } body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html>
浏览器访问测试
伸缩应用程序
Scaling(伸缩)应用程序
我们发布的 Deployment 只创建了一个 Pod 来运行我们的应用程序。当流量增加时,我们需要对应用程序进行伸缩操作以满足系统性能需求。
伸缩 的实现可以通过更改 nginx-deployment.yaml 文件中部署的 replicas(副本数)来完成,例如:
spec: replicas: 4
下图中,Service A 只将访问流量转发到 IP 为 10.0.0.5 的Pod上。
修改了 Deployment 的 replicas 为 4 后,Kubernetes 又为该 Deployment 创建了 3 新的 Pod,这 4 个 Pod 有相同的标签。因此Service A通过标签选择器与新的 Pod建立了对应关系,将访问流量通过负载均衡在 4 个 Pod 之间进行转发。如下图所示。
将Deployment扩容到4个副本
修改 nginx-deployment.yaml 文件
将 spec.replicas 的值修改为 4
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 4
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
执行命令
[root@k8s-master01 1]# kubectl apply -f nginx-deployment.yaml deployment.apps/nginx-deployment configured
查看结果
[root@k8s-master01 1]# watch kubectl get pods -o wide
滚动更新持续一段时间后,4个pods都变为Running状态。
按Ctrl+C返回命令行。
访问Nginx服务
[root@k8s-master01 1]# curl localhost:32600 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> html { color-scheme: light dark; } body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html>
查看pod日志
[root@k8s-master01 1]# kubectl logs -f nginx-deployment-9c65654f4-dcvtj /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/ /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh 10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf 10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf /docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh /docker-entrypoint.sh: Configuration complete; ready for start up 2024/10/10 03:16:59 [notice] 1#1: using the "epoll" event method 2024/10/10 03:16:59 [notice] 1#1: nginx/1.27.2 2024/10/10 03:16:59 [notice] 1#1: built by gcc 13.2.1 20240309 (Alpine 13.2.1_git20240309) 2024/10/10 03:16:59 [notice] 1#1: OS: Linux 5.14.0-427.33.1.el9_4.x86_64 2024/10/10 03:16:59 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1073741816:1073741816 2024/10/10 03:16:59 [notice] 1#1: start worker processes 2024/10/10 03:16:59 [notice] 1#1: start worker process 30 2024/10/10 03:16:59 [notice] 1#1: start worker process 31 2024/10/10 03:16:59 [notice] 1#1: start worker process 32 2024/10/10 03:16:59 [notice] 1#1: start worker process 33 192.168.204.101 - - [10/Oct/2024:08:02:42 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.76.1" "-" 192.168.204.101 - - [10/Oct/2024:08:02:55 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.76.1" "-"
再多次访问32600,观察日志输出变化
[root@k8s-master01 1]# curl localhost:32600
可以看到访问几次,日志才发生变化,说明每次都由不同的pod提供服务,达到多个pod分担访问压力的效果,实现了访问的负载均衡。
感兴趣可以同时访问多个pod日志,再多次访问32600端口,观察多个pod日志的变化情况。
将Deployment缩容到2个副本
修改 nginx-deployment.yaml
[root@k8s-master01 1]# vi nginx-deployment.yaml
修改spec.replicas由4改为2,如下
spec: replicas: 2
应用部署文件
[root@k8s-master01 1]# kubectl apply -f nginx-deployment.yaml deployment.apps/nginx-deployment configured
监听pod变化
[root@k8s-master01 1]# watch kubectl get pods -o wide
看到只有两个pod了,实现了部署缩容。
滚动更新应用
滚动更新概述
用户期望应用程序始终可用,为此开发者/运维者在更新应用程序时要分多次完成。在 Kubernetes 中,这是通过 Rolling Update 滚动更新完成的。Rolling Update滚动更新 通过使用新版本的 Pod 逐步替代旧版本的 Pod 来实现 Deployment 的更新,从而实现零停机。新的 Pod 将在具有可用资源的 Node(节点)上进行调度。
Kubernetes 更新多副本的 Deployment 的版本时,会逐步的创建新版本的 Pod,逐步的停止旧版本的 Pod,以便使应用一直处于可用状态。这个过程中,Service 能够监视 Pod 的状态,将流量始终转发到可用的 Pod 上。
此前,我们将应用程序 Scale Up(扩容)为多个实例,这是执行更新而不影响应用程序可用性的前提。默认情况下,Rolling Update 滚动更新 过程中,Kubernetes 逐个使用新版本 Pod 替换旧版本 Pod(最大不可用 Pod 数为 1、最大新建 Pod 数也为 1)。这两个参数可以配置为数字或百分比。在Kubernetes 中,更新是版本化的,任何部署更新都可以恢复为以前的(稳定)版本。
滚动更新步骤
1.原本 Service A 将流量负载均衡到 4 个旧版本的 Pod (当中的容器为 绿色)上
2.更新完 Deployment 部署文件中的镜像版本后,Master 节点选择了一个 Node节点,并根据新的镜像版本创建 Pod(紫色容器)。新 Pod 拥有唯一的新的 IP。同时,master 节点选择一个旧版本的 Pod 将其移除。
此时,Service A 将新 Pod 纳入到负载均衡中,将旧Pod移除
3.同步骤2,再创建一个新的 Pod 替换一个原有的 Pod
4.如此 Rolling Update 滚动更新,直到所有旧版本 Pod 均移除,新版本 Pod 也达到 Deployment 部署文件中定义的副本数,则滚动更新完成
滚动更新允许以下操作:
-
将应用程序从准上线环境升级到生产环境(通过更新容器镜像)
-
回滚到以前的版本
-
持续集成和持续交付应用程序,无需停机
滚动更新Deployment
按照上一节的方法,将pod扩容到4个
修改 nginx-deployment.yaml 文件
修改文件中 image 镜像的标签,如下所示
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx spec: replicas: 4 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.27.2 #使用镜像nginx:1.27.2替换原来的nginx:alpine ports: - containerPort: 80
执行命令
kubectl apply -f nginx-deployment.yaml
查看过程及结果
执行命令,可观察到 pod 逐个被替换的过程。
watch kubectl get pods -l app=nginx
注意:如果之前已经有1.27.2镜像,替换过程会比较快,执行watch命令的较晚的话,可能看不多替换过程或者只能看到部分替换过程。要看到全部替换过程,可以先执行这个watch命令,在执行kubectl apply命令。
原来的nginx-deployment-9c65654f4相关的pods从4个变为只有1个;新的nginx-deployment-75b5b48df5相关pods,有两个pod已经创建好了,有两个pod正在容器创建。
k2cjr已经创建成功如下
已经新的pods全部创建成功,可以观察到pod名称都是新的pod了。
查看ip也都变化了
浏览器访问
删除部署资源
相关命令
删除 Deployment
Deployment 是用于管理应用的 Pod 副本数量和更新策略的资源对象。通过删除 Deployment,会自动删除其管理的 Pod。
kubectl delete deployment <deployment_name>
删除 Service
如果应用使用了 Service 来暴露服务,那么也需要删除对应的 Service。
kubectl delete service <service_name>
删除其他相关资源
根据应用的具体配置,可能还需要删除其他相关的资源,如 ConfigMap、Secret 等。
kubectl delete configmap <configmap_name> kubectl delete secret <secret_name>
查看是否已删除成功
可以使用 kubectl get
命令来确认相关资源是否已被成功删除。例如:
kubectl get deployment <deployment_name> kubectl get service <service_name> kubectl get configmap <configmap_name> kubectl get secret <secret_name>
如果资源已被成功删除,上述命令将不会返回对应的资源信息。
强制删除
如果在删除过程中遇到问题,例如 Pod 处于 Terminating 状态无法正常删除,可以使用强制删除的方式。
kubectl delete pod <pod_name> --force --grace-period=0
这种方式会立即删除 Pod,而不会等待其正常的终止流程完成。但在使用强制删除时需要谨慎,因为可能会导致数据丢失或其他未预期的问题。
命名空间删除
如果应用部署在特定的命名空间中,并且希望彻底删除该命名空间及其内的所有资源,可以使用以下命令:
kubectl delete namespace <namespace_name>
这将删除指定命名空间下的所有 Deployment、Service、Pod 等资源。
在执行删除操作时,请确保你有足够的权限,并且仔细确认要删除的资源,以免误删导致数据丢失或服务中断。
删除部署资源
查看部署的资源
# 查看deployment资源 [root@k8s-master01 1]# kubectl get deployment NAME READY UP-TO-DATE AVAILABLE AGE nginx-deployment 4/4 4 4 25h # 查看service资源 [root@k8s-master01 1]# kubectl get service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 59d nginx-service NodePort 10.3.21.175 <none> 80:32600/TCP 107m
删除service
# 删除service资源 [root@k8s-master01 1]# kubectl delete service nginx-service service "nginx-service" deleted # 查看service资源 [root@k8s-master01 1]# kubectl get service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 59d
删除deployment资源
# 删除deployment资源 [root@k8s-master01 1]# kubectl delete deployment nginx-deployment deployment.apps "nginx-deployment" deleted # 查看deployment资源 [root@k8s-master01 1]# kubectl get deployment No resources found in default namespace.
完成!enjoy it!