前言
在 Kubernetes 集群中,通过陈述式和声明式资源管理是确保应用程序高效运行的关键。认识这两种管理方法,能够更好地掌握 Kubernetes 集群的运维和管理。
目录
一、K8s 资源管理操作分类
1. 陈述式
2. 声明式
3. K8s 集群管理常用命令概览
二、 kubectl 命令实例
1. 基本信息查看
1.1 基本格式
1.2 查看 master 节点状态
1.3 查看命名空间
1.4 查看 default 命名空间的所有资源
1.5 创建命名空间 fql
1.6 删除命名空间
1.7 在命名空间 fql 创建副本控制器(deployment)来启动Pod(nginx-01)
1.8 描述资源的详细信息
1.9 查看命名空间 fql 中的 pod 信息
1.10 登录容器
1.11 删除(重启)pod 资源
1.12 扩缩容
1.13 删除副本控制器
三、项目的生命周期
1. 创建 kubectl create 命令
2. 发布 kubectl expose 命令
2.1 将资源暴露为新的 Service
2.1.1 Kubernetes 之所以需要 Service
2.1.2 service 的 type 类型
2.1.3 无头模式 headless clusterIP
2.1.4 端口类型
2.2 查看 pod 网络状态详细信息和 Service 暴露的端口
2.3 查看关联后端的节点
2.4 查看 service 的描述信息
2.5 查看负载均衡端口
3. 更新版本 kubectl set
3.1 查看当前 nginx 的版本号
3.2 获取修改模板
3.3 滚动更新
4. 回滚 kubectl rollout
4.1 查看回滚指令帮助说明
4.2 查看历史版本
4.3 执行回滚到上一个版本
4.4 执行回滚到指定版本
4.5 检查回滚状态
5. 删除 kubectl delete
5.1 删除副本控制器
5.2 删除 service
6. 金丝雀发布(灰度发布)
6.1 更新 deployment 的版本,并配置暂停 deployment
6.2 开启另一个窗口查看 pod 信息
6.3 确保更新的 pod 没问题,继续更新
6.4 查看最后的更新情况
6.5 分阶段访问
7. 蓝绿发布
8. 发布方式总结
一、K8s 资源管理操作分类
1. 陈述式
通过 kubectl 命令的方式来实现对资源进行管理,简而言之,就是通过一条命令来实现操作,如查看节点信息等;对资源的增、删、查操作比较方便,但对改的操作就不容易了。
kubectl 是官方的 CLI 命令行工具,用于与 apiserver 进行通信,将用户在命令行输入的命令,组织并转化为 apiserver 能识别的信息,进而实现管理 k8s 各种资源的一种有效途径。
kubectl 的命令大全
k8s中文文档:Kubernetes kubectl 命令表 _ Kubernetes(K8S)中文文档_Kubernetes中文社区
2. 声明式
通过使用 yaml 或 josn 文件对资源配置,然后再实现对资源的管理。
3. K8s 集群管理常用命令概览
① 查看版本信息
[root@master01 ~]# kubectl version
Client Version: version.Info{Major:"1", Minor:"20", GitVersion:"v1.20.11", GitCommit:"27522a29febbcc4badac257763044d0d90c11abd", GitTreeState:"clean", BuildDate:"2021-09-15T19:21:44Z", GoVersion:"go1.15.15", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"20", GitVersion:"v1.20.11", GitCommit:"27522a29febbcc4badac257763044d0d90c11abd", GitTreeState:"clean", BuildDate:"2021-09-15T19:16:25Z", GoVersion:"go1.15.15", Compiler:"gc", Platform:"linux/amd64"}
② 查看资源对象简写
[root@master01 ~]# kubectl api-resources
③ 查看集群信息
[root@master01 ~]# kubectl cluster-info
Kubernetes control plane is running at https://192.168.190.100:6443
KubeDNS is running at https://192.168.190.100:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
④ 配置 kubectl 自动补全
[root@master01 ~]# source <(kubectl completion bash)
⑤ node 节点查看日志
[root@node01 ~]# journalctl -u kubelet -f
-- Logs begin at 四 2024-05-16 14:11:00 CST. --
5月 16 23:10:52 node01 kubelet[40583]: I0516 23:10:52.598264 40583 topology_manager.go:187] [topologymanager] Topology Admit Handler
5月 16 23:10:52 node01 kubelet[40583]: I0516 23:10:52.722290 40583 reconciler.go:224] operationExecutor.VerifyControllerAttachedVolume started for volume "default-token-n27bv" (UniqueName: "kubernetes.io/secret/7df6ee9c-aca5-4195-8611-43684869cee9-default-token-n27bv") pod "nginx-deployment-7dc776dfc6-nt2px" (UID: "7df6ee9c-aca5-4195-8611-43684869cee9")
错误日志实例:
节点 192.168.190.102 的 kubelet 服务无法更新节点状态,因为无法连接到 192.168.190.200:6443:
[root@node01 ~]# journalctl -f -u kubelet.service
-- Logs begin at 一 2024-05-13 10:23:14 CST. --
5月 16 10:53:04 node01 kubelet[59283]: E0516 10:53:04.821047 59283 kubelet_node_status.go:470] Error updating node status, will retry: error getting node "192.168.190.102": Get "https://192.168.190.200:6443/api/v1/nodes/192.168.190.102?timeout=10s": dial tcp 192.168.190.200:6443: connect: no route to host
5月 16 10:53:07 node01 kubelet[59283]: E0516 10:53:07.825185 59283 kubelet_node_status.go:470] Error updating node status, will retry: error getting node "192.168.190.102": Get "https://192.168.190.200:6443/api/v1/nodes/192.168.190.102?timeout=10s": dial tcp 192.168.190.200:6443: connect: no route to host
# journalctl: 是 Systemd 系统日志查询工具,用于查看和管理 systemd 初始化系统产生的日志。
# -f: 参数表示跟随模式,即在终端上持续显示新的日志条目,这对于监视服务的实时运行状况非常有用。
# -u kubelet.service: 指定查看 kubelet.service 这个 Systemd 单元的服务日志。kubelet 是 Kubernetes 的核心组件之一,负责在每个节点上运行容器,管理 pod 状态并与 Kubernetes 主控进行通信。
二、 kubectl 命令实例
1. 基本信息查看
1.1 基本格式
获取资源的相关信息:
kubectl get <resource> [-o wide|json|yaml] [-n namespace]
# -n 指定命令空间
# -o 指定输出格式
# resource可以是具体资源名称,如:pod nginx-xxx;也可以是资源类型,如pod:或者all等
# --all-namespaces 或 -A:表示显示所有命令空间
# --show-labels:显示所有标签
# -l app:仅显示标签为app的资源
# -l app=nginx:仅显示包含app标签,且值为nginx的资源
1.2 查看 master 节点状态
[root@master01 ~]# kubectl get componentstatuses
Warning: v1 ComponentStatus is deprecated in v1.19+
NAME STATUS MESSAGE ERROR
scheduler Healthy ok
controller-manager Healthy ok
etcd-0 Healthy {"health":"true"}
简写:
kubectl get cs
1.3 查看命名空间
在 K8s 中,命名空间(Namespace)是用来将集群中的资源进行逻辑隔离的一种方式。通过命名空间,可以将集群中的资源划分为不同的逻辑单元,允许不同命名空间相同类型的资源重名。
[root@master01 ~]# kubectl get namespaces 简写:kubectl get ns
NAME STATUS AGE
default Active 22h # 默认空间
kube-flannel Active 21h
kube-node-lease Active 22h
kube-public Active 22h
kube-system Active 22h
kubernetes-dashboard Active 20h
[root@master01 ~]# kubectl get pod -n kube-flannel
# 获取命名空间kube-flannel中的所有Pod资源的信息
NAME READY STATUS RESTARTS AGE
kube-flannel-ds-bctwm 1/1 Running 1 21h
kube-flannel-ds-w8zmz 1/1 Running 0 21h
kube-flannel-ds-wz8p2 1/1 Running 3 21h
[root@master01 ~]# kubectl get pod -n kube-flannel -o wide
# -o wide参数来显示更多关于Pod资源的详细信息,包括IP地址、Node名称、状态等
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
kube-flannel-ds-bctwm 1/1 Running 1 21h 192.168.190.102 node02 <none> <none>
kube-flannel-ds-w8zmz 1/1 Running 0 22h 192.168.190.100 master01 <none> <none>
kube-flannel-ds-wz8p2 1/1 Running 3 21h 192.168.190.101 node01 <none> <none>
[root@master01 ~]# kubectl get node
# 获取所有Node资源的信息
NAME STATUS ROLES AGE VERSION
master01 Ready control-plane,master 23h v1.20.11
node01 Ready <none> 21h v1.20.11
node02 Ready <none> 21h v1.20.11
注意:
- 在Kubernetes中,Node资源是全局资源,不属于任何特定的命名空间
- 无论是否使用-n kube-flannel参数,获取Node资源的信息都将是相同的
- 因为Node资源是集群级别的资源,而不是特定于某个命名空间的资源
1.4 查看 default 命名空间的所有资源
格式:
kubectl get all [-n default]
[root@master01 ~]# kubectl get all -n kube-flannel
NAME READY STATUS RESTARTS AGE
pod/kube-flannel-ds-bctwm 1/1 Running 1 21h
pod/kube-flannel-ds-w8zmz 1/1 Running 0 22h
pod/kube-flannel-ds-wz8p2 1/1 Running 3 21h
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
daemonset.apps/kube-flannel-ds 3 3 3 3 3 <none> 22h
# 这个DaemonSet的期望副本数(DESIRED)是3
# 当前副本数(CURRENT)是3
# 所有的副本都处于Ready状态(READY=3)并且都是最新版本(UP-TO-DATE=3)
# 所有的副本都是可用的(AVAILABLE=3)
# 这个DaemonSet没有指定Node选择器(NODE SELECTOR为)
1.5 创建命名空间 fql
[root@master01 ~]# kubectl create ns fql
namespace/fql created
[root@master01 ~]# kubectl get ns | grep fql
fql Active 7s
1.6 删除命名空间
格式:
kubectl delete namespace <namespace_name>
kubectl delete ns <namespace_name>
注意:
删除命名空间将删除该命名空间中的所有资源,包括Pods、Services、Deployments等
Deployment是Kubernetes中用于管理Pod部署和更新的重要资源对象
1.7 在命名空间 fql 创建副本控制器(deployment)来启动Pod(nginx-01)
[root@master01 ~]# kubectl create deployment nginx-01 --image=nginx -n fql
deployment.apps/nginx-01 created
[root@master01 ~]# kubectl get pod -n fql
NAME READY STATUS RESTARTS AGE
nginx-01-796cd9986d-7j8kd 1/1 Running 0 57s
1.8 描述资源的详细信息
描述位于fql命名空间中,名为nginx-01的Deployment资源对象的详细信息:
[root@master01 ~]# kubectl describe deployment nginx-01 -n fql
描述位于fql命名空间中,名为nginx-01-796cd9986d-7j8kd的Pod资源对象的详细信息:
[root@master01 ~]# kubectl describe pod nginx-01-796cd9986d-7j8kd -n fql
查看具有标签app=nginx-01的所有Pod的日志信息,这些Pod位于fql命名空间中:
[root@master01 ~]# kubectl logs -l app=nginx-01 -n fql
查看名为nginx-01-796cd9986d-7j8kd的特定Pod的日志信息,该Pod位于fql命名空间中:
[root@master01 ~]# kubectl logs nginx-01-796cd9986d-7j8kd -n fql
1.9 查看命名空间 fql 中的 pod 信息
[root@master01 ~]# kubectl get pod -n fql
NAME READY STATUS RESTARTS AGE
nginx-01-796cd9986d-7j8kd 1/1 Running 0 69m
1.10 登录容器
kubectl exec 可以跨主机登录容器,docker exec 只能在容器所在主机上登录
[root@master01 ~]# kubectl exec -it nginx-01-796cd9986d-7j8kd -n fql bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@nginx-01-796cd9986d-7j8kd:/# exit
exit
1.11 删除(重启)pod 资源
由于存在 deployment/rc 之类的副本控制器,删除 pod 也会重新拉起来
创建pod副本:
[root@master01 ~]# kubectl create deployment nginx-02 --image=nginx -n fql --replicas=3
deployment.apps/nginx-02 created
查看pod状态:
[root@master01 ~]# kubectl get pod -o wide -n fql
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-01-796cd9986d-7j8kd 1/1 Running 0 3d3h 10.244.2.7 node02 <none> <none>
nginx-02-5d68d7dd6c-7dwk4 1/1 Running 0 2m6s 10.244.2.8 node02 <none> <none>
nginx-02-5d68d7dd6c-kq2bn 1/1 Running 0 2m6s 10.244.1.13 node01 <none> <none>
nginx-02-5d68d7dd6c-rg9np 1/1 Running 0 2m6s 10.244.1.12 node01 <none> <none>
删除一个pod,再次查看 pod ip 信息:
[root@master01 ~]# kubectl delete pod nginx-02-5d68d7dd6c-rg9np -n fql
pod "nginx-02-5d68d7dd6c-rg9np" deleted
[root@master01 ~]# kubectl get pod -o wide -n fql
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-01-796cd9986d-7j8kd 1/1 Running 0 3d3h 10.244.2.7 node02 <none> <none>
nginx-02-5d68d7dd6c-7dwk4 1/1 Running 0 3m25s 10.244.2.8 node02 <none> <none>
nginx-02-5d68d7dd6c-kkbd5 1/1 Running 0 28s 10.244.2.9 node02 <none> <none>
nginx-02-5d68d7dd6c-kq2bn 1/1 Running 0 3m25s 10.244.1.13 node01 <none> <none>
若 pod 无法删除,总是处于 terminate 状态,则要强行删除 pod
kubectl delete pod <pod-name> -n <namespace> --force --grace-period=0
# grace-period表示过渡存活期,默认30s,在删除pod之前允许POD慢慢终止其上的容器进程,从而优雅退出
# 0表示立即终止pod
1.12 扩缩容
扩容:
[root@master01 ~]# kubectl scale deployment nginx-01 --replicas=2 -n fql
deployment.apps/nginx-01 scaled
[root@master01 ~]# kubectl get pod -n fql
NAME READY STATUS RESTARTS AGE
nginx-01-796cd9986d-7j8kd 1/1 Running 0 3d3h
nginx-01-796cd9986d-c98q2 1/1 Running 0 18s
nginx-02-5d68d7dd6c-7dwk4 1/1 Running 0 13m
nginx-02-5d68d7dd6c-kkbd5 1/1 Running 0 10m
nginx-02-5d68d7dd6c-kq2bn 1/1 Running 0 13m
缩容:
[root@master01 ~]# kubectl scale deployment nginx-02 --replicas=1 -n fql
deployment.apps/nginx-02 scaled
[root@master01 ~]# kubectl get pod -n fql
NAME READY STATUS RESTARTS AGE
nginx-01-796cd9986d-7j8kd 1/1 Running 0 3d3h
nginx-01-796cd9986d-c98q2 1/1 Running 0 48s
nginx-02-5d68d7dd6c-kq2bn 1/1 Running 0 14m
1.13 删除副本控制器
删除副本控制器将同时删除由该副本控制器管理的所有Pod副本
[root@master01 ~]# kubectl delete deployment nginx-02 -n fql
deployment.apps "nginx-02" deleted
[root@master01 ~]# kubectl get pod -n fql
NAME READY STATUS RESTARTS AGE
nginx-01-796cd9986d-7j8kd 1/1 Running 0 3d3h
nginx-01-796cd9986d-c98q2 1/1 Running 0 2m28s
nginx-02-5d68d7dd6c-kq2bn 0/1 Terminating 0 16m # 正在被删除
[root@master01 ~]# kubectl get pod -n fql
NAME READY STATUS RESTARTS AGE
nginx-01-796cd9986d-7j8kd 1/1 Running 0 3d3h
nginx-01-796cd9986d-c98q2 1/1 Running 0 3m43s
三、项目的生命周期
Kubernetes 项目的生命周期包括设计、开发、部署、运行和维护等阶段。在设计和开发阶段,需要定义应用程序的架构和容器镜像,以及创建 Kubernetes 资源对象。在部署和运行阶段,需要使用 kubectl 命令将应用程序部署到 Kubernetes 集群中,并进行监控和维护。即:创建-->发布-->更新-->回滚-->删除。
1. 创建 kubectl create 命令
- 创建并运行一个或多个容器镜像
- 创建一个 deployment 或 job 来管理容器
启动 nginx 实例,暴露容器端口 80,设置副本数 3
[root@master01 ~]# kubectl create deployment nginx-01 --image=nginx:1.14 --port=80 --replicas=3 -n fql
deployment.apps/nginx-01 created
[root@master01 ~]# kubectl get pod -o wide -n fql
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-01-799fb6fb65-296dl 1/1 Running 0 24s 10.244.1.18 node01 <none> <none>
nginx-01-799fb6fb65-jhqt2 1/1 Running 0 24s 10.244.1.19 node01 <none> <none>
nginx-01-799fb6fb65-kqbc2 1/1 Running 0 24s 10.244.2.13 node02 <none> <none>
2. 发布 kubectl expose 命令
2.1 将资源暴露为新的 Service
为 deployment 的 nginx 创建 service,并通过 Service 的80端口转发至容器的80端口上,Service的名称为 nginx-service,类型为 NodePort。
[root@master01 ~]# kubectl expose deployment nginx-01 -n fql --port=80 --target-port=80 --name=nginx-server --type=NodePort
service/nginx-server exposed
2.1.1 Kubernetes 之所以需要 Service
- 一方面是因为 Pod 的 IP 不是固定的(Pod可能会重建)
- 另一方面则是因为一组 Pod 实例之间总会有负载均衡的需求
- 对于容器应用而言,Kubernetes 提供了基于 VIP(虚拟IP) 的网桥的方式访问 Service,再由 Service 重定向到相应的 Pod
2.1.2 service 的 type 类型
- ClusterIP:提供一个集群内部的虚拟IP以供Pod访问(service默认类型)
- NodePort:在每个Node上打开一个端口以供外部访问,Kubernetes将会在每个Node上打开一个端口并且每个Node的端口都是一样的,通过 NodeIp:NodePort 的方式Kubernetes集群外部的程序可以访问Service
- 每个端口只能是一种服务,端口范围只能是 30000-32767
- LoadBalancer:通过设置LoadBalancer映射到云服务商提供的LoadBalancer地址。这种用法仅用于在公有云服务提供商的云平台上设置Service的场景。通过外部的负载均衡器来访问,通常在云平台部署LoadBalancer还需要额外的费用
- 在service提交后,Kubernetes就会调用CloudProvider在公有云上为你创建一个负载均衡服务,并且把被代理的Pod的IP地址配置给负载均衡服务做后端
- externalName:将service名称映射到一个DNS域名上,相当于DNS服务的CNAME记录,用于让Pod去访问集群外部的资源,它本身没有绑定任何的资源。 tgc.benet.com www.benet.com
2.1.3 无头模式 headless clusterIP
- 是Kubernetes中一种特殊类型的服务,它不会为服务创建ClusterIP,而是直接将DNS解析指向服务的每个Pod的IP地址。这种模式适用于需要直接与每个Pod进行通信的场景,而不需要负载均衡或代理。
2.1.4 端口类型
① port
- port 是 k8s 集群内部访问 service 的端口,即通过 clusterIP: port 可以从 Pod 所在的 Node 上访问到 service(四层)
② nodePort
- nodePort 是外部访问 k8s 集群中 service 的端口,通过 nodeIP: nodePort 可以从外部访问到某个 service
③ targetPort
- targetPort 是 Pod 的端口,从 port 或 nodePort 来的流量经过 kube-proxy 反向代理负载均衡转发到后端 Pod 的 targetPort 上,最后进入容器
④ containerPort
- containerPort 是 Pod 内部容器的端口,targetPort 映射到 containerPort
2.2 查看 pod 网络状态详细信息和 Service 暴露的端口
[root@master01 ~]# kubectl get pod,svc -o wide -n fql
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/nginx-01-799fb6fb65-296dl 1/1 Running 0 90s 10.244.1.18 node01 <none> <none>
pod/nginx-01-799fb6fb65-jhqt2 1/1 Running 0 90s 10.244.1.19 node01 <none> <none>
pod/nginx-01-799fb6fb65-kqbc2 1/1 Running 0 90s 10.244.2.13 node02 <none> <none>
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service/nginx-server NodePort 10.96.153.145 <none> 80:32591/TCP 32s app=nginx-01
使用客户端浏览器访问任意一个节点ip的32591端口,都可以访问到nginx的pod实例
[root@master01 ~]# curl 192.168.190.101:32591
<title>Welcome to nginx!</title>
[root@master01 ~]# curl 192.168.190.102:32591
<title>Welcome to nginx!</title>
2.3 查看关联后端的节点
[root@master01 ~]# kubectl get endpoints -n fql
NAME ENDPOINTS AGE
nginx-server 10.244.1.18:80,10.244.1.19:80,10.244.2.13:80 75s
2.4 查看 service 的描述信息
[root@master01 ~]# kubectl describe svc nginx -n fql
Name: nginx-server # Service的名称为nginx-server
Namespace: fql # Service位于fql命名空间中
Labels: app=nginx-01 # Service的标签为app=nginx-01
Annotations: <none> # Service没有任何注释信息
Selector: app=nginx-01 # Service通过标签选择器app=nginx-01选择与之匹配的Pod
Type: NodePort # Service的类型为NodePort,表示将Service暴露到集群外部,并使用Node的IP地址和端口号来访问Service
IP Families: <none> # Service没有指定IP地址族
IP: 10.96.153.145 # Service的IP地址为10.96.153.145
IPs: 10.96.153.145 # Service的IP地址为10.96.153.145
Port: <unset> 80/TCP # Service暴露的端口号为80,使用TCP协议
TargetPort: 80/TCP # Service将请求转发到Pod的端口号为80,使用TCP协议
NodePort: <unset> 32591/TCP # Service将使用Node的IP地址和端口号32591来暴露Service,使用TCP协议
Endpoints: 10.244.1.18:80,10.244.1.19:80,10.244.2.13:80 # Service的后端是3个Pod
Session Affinity: None # Service没有启用会话亲和性
External Traffic Policy: Cluster # Service的外部流量策略为Cluster
Events: <none> # Service没有任何事件记录
2.5 查看负载均衡端口
node01 节点上操作
[root@node01 ~]# yum install ipvsadm -y
[root@node01 ~]# ipvsadm -Ln
TCP 172.17.0.1:32591 rr
-> 10.244.1.18:80 Masq 1 0 0
-> 10.244.1.19:80 Masq 1 0 0
-> 10.244.2.13:80 Masq 1 0 0
# docker网桥
TCP 192.168.190.101:32591 rr
-> 10.244.1.18:80 Masq 1 0 0
-> 10.244.1.19:80 Masq 1 0 0
-> 10.244.2.13:80 Masq 1 0 1
# 外部访问的ip和端口
TCP 10.96.153.145:80 rr
-> 10.244.1.18:80 Masq 1 0 0
-> 10.244.1.19:80 Masq 1 0 0
-> 10.244.2.13:80 Masq 1 0 0
# pod集群组内部访问的ip和端口
在 node02 节点上操作,同样方式也可以查看负载均衡端口
修改各pod访问界面为自定义界面:
[root@master01 ~]# kubectl get pod -n fql
NAME READY STATUS RESTARTS AGE
nginx-01-799fb6fb65-296dl 1/1 Running 0 28m
nginx-01-799fb6fb65-jhqt2 1/1 Running 0 28m
nginx-01-799fb6fb65-kqbc2 1/1 Running 0 28m
[root@master01 ~]# kubectl exec -it nginx-01-799fb6fb65-296dl bash -n fql
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@nginx-01-799fb6fb65-296dl:/# echo web01 > /usr/share/nginx/html/index.html
[root@master01 ~]# kubectl exec -it nginx-01-799fb6fb65-jhqt2 bash -n fql
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@nginx-01-799fb6fb65-jhqt2:/# echo web02 > /usr/share/nginx/html/index.html
[root@master01 ~]# kubectl exec -it nginx-01-799fb6fb65-kqbc2 bash -n fql
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@nginx-01-799fb6fb65-kqbc2:/# echo web03 > /usr/share/nginx/html/index.html
验证负载均衡:
[root@master01 ~]# kubectl get svc -n fql
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-server NodePort 10.96.153.145 <none> 80:32591/TCP 30m
[root@master01 ~]# curl 10.96.153.145
web03
[root@master01 ~]# curl 10.96.153.145
web02
[root@master01 ~]# curl 10.96.153.145
web01
3. 更新版本 kubectl set
Kubernetes 更新版本通常会涉及 kubectl set 命令的功能改进和参数扩展,以便更方便地管理和更新资源的字段,如扩展副本数量、更改镜像标签等。
3.1 查看当前 nginx 的版本号
[root@master01 ~]# curl 10.96.153.145 -I
Server: nginx/1.14.2
3.2 获取修改模板
[root@master01 ~]# kubectl set image --help
Examples:
# Set a deployment's nginx container image to 'nginx:1.9.1', and its busybox
container image to 'busybox'.
kubectl set image deployment/nginx busybox=busybox nginx=nginx:1.9.1
3.3 滚动更新
将nginx 版本更新为 1.15 版本
[root@master01 ~]# kubectl set image deployment/nginx-01 nginx=nginx:1.15 -n fql
deployment.apps/nginx-01 image updated
[root@master01 ~]# kubectl get pod -n fql
NAME READY STATUS RESTARTS AGE
nginx-01-78cb4c6b78-2h46w 1/1 Running 0 28s
nginx-01-78cb4c6b78-fwvkv 0/1 ContainerCreating 0 10s
nginx-01-799fb6fb65-jhqt2 1/1 Running 0 41m
nginx-01-799fb6fb65-kqbc2 1/1 Running 0 41m
[root@master01 ~]# kubectl get pod -n fql
NAME READY STATUS RESTARTS AGE
nginx-01-78cb4c6b78-2h46w 1/1 Running 0 55s
nginx-01-78cb4c6b78-2ldxl 1/1 Running 0 7s
nginx-01-78cb4c6b78-fwvkv 1/1 Running 0 37s
nginx-01-799fb6fb65-jhqt2 0/1 Terminating 0 41m
……
……
处于动态监听 pod 状态,由于使用的是滚动更新方式,所以会先生成一个新的pod,然后删除一个旧的pod,往后依次类推:
kubectl get pods -w
# 更新好后的Pod的ip会改变
[root@master01 ~]# curl 10.96.153.145 -I
Server: nginx/1.15.12
- 首先在确保正常提供服务的情况下,在三个 pod 实例正常运行的情况下,生成一个新的指定版本的 pod 实例
- 等到新的 pod 实例创建成功后并验证可用性,会删除第一个 pod 实例
- 而后再生成第二个新版本的 pod 实例,再删除第二个,依此类推,一直到该 deployment 下的所有 pod 资源全部升级完毕
需要注意的是,资源更新后,其原本 pod 实例中的数据并不会被继承。如果有需要的话,可以先对数据进行备份,等到升级完毕后,再同步数据。
4. 回滚 kubectl rollout
Kubernetes 中的回滚操作通常使用 kubectl rollout 命令,该命令允许用户回退到先前的部署版本,同时保留集群的稳定性。这包括查看历史记录、回滚到特定版本以及监视回滚过程。
4.1 查看回滚指令帮助说明
kubectl rollout --help
4.2 查看历史版本
[root@master01 ~]# kubectl rollout history deployment/nginx-01 -n fql
deployment.apps/nginx-01
REVISION CHANGE-CAUSE
1 <none>
2 <none>
REVISION #显示历史中的每个版本,最多记录三次
CHANGE-CAUSE #显示触发该版本变更的原因。显示为 <none>,表示没有明确的变更原因被记录
# Kubernetes本身不会自动为每次Deployment的更新填充CHANGE-CAUSE字段。
# 这个字段通常是通过设置 Deployment 的注解(annotation)来填充的
# 特别是 kubernetes.io/change-cause 这个注解。
4.3 执行回滚到上一个版本
[root@master01 ~]# kubectl rollout undo deployment/nginx-01 -n fql
deployment.apps/nginx-01 rolled back
4.4 执行回滚到指定版本
格式:
kubectl rollout undo deployment/nginx --to-revision=1
# 将名为nginx的部署回滚到版本1,即撤销最近的更改并还原到特定的先前版本。
4.5 检查回滚状态
[root@master01 ~]# kubectl rollout status deployment/nginx-01 -n fql
deployment "nginx-01" successfully rolled out
[root@master01 ~]# curl 10.96.153.145 -I
Server: nginx/1.14.2
5. 删除 kubectl delete
kubectl delete 命令用于删除 Kubernetes 集群中的资源,可以是 pod、service、deployment 等。用户可以通过指定资源类型和名称来删除特定的资源,也可以使用标签选择器来批量删除符合条件的资源。
5.1 删除副本控制器
[root@master01 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-deployment-7dc776dfc6-4vm79 1/1 Running 0 60m
nginx-deployment-7dc776dfc6-b7qvn 1/1 Running 0 60m
nginx-deployment-7dc776dfc6-lzzvb 1/1 Running 0 60m
[root@master01 ~]# kubectl delete deployment nginx-deployment
deployment.apps "nginx-deployment" deleted
5.2 删除 service
[root@master01 ~]# kubectl get service -n fql
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-server NodePort 10.96.153.145 <none> 80:32591/TCP 60m
[root@master01 ~]# kubectl delete service nginx-server -n fql
service "nginx-server" deleted
6. 金丝雀发布(灰度发布)
Deployment 控制器支持自定义控制更新过程中的滚动节奏,如“暂停(pause)”或“继续(resume)”更新操作。
- 比如等待第一批新的Pod资源创建完成后立即暂停更新过程,此时,仅存在一部分新版本的应用,主体部分还是旧的版本;
- 然后,再筛选一小部分的用户请求路由到新版本的Pod应用,继续观察能否稳定地按期望的方式运行;
- 确定没问题之后再继续完成余下的Pod资源滚动更新,否则立即回滚更新操作。这就是所谓的金丝雀发布。
准备工作:
[root@master01 ~]# kubectl delete deployments.apps nginx-01 -n fql
# 删除名为"nginx-01"的部署(Deployment)在命名空间(Namespace)"fql"中的实例
[root@master01 ~]# kubectl delete svc nginx
[root@master01 ~]# kubectl delete svc nginx-deployment
[root@master01 ~]# kubectl delete svc nginx-service -n fql
# 删除 Kubernetes 集群中的服务(Service)
[root@master01 ~]# kubectl create deployment nginx-01 --image=nginx:1.14 --port=80 --replicas=3 -n fql
deployment.apps/nginx-01 created
[root@master01 ~]# kubectl get pod -o wide -n fql
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-01-799fb6fb65-7c29k 1/1 Running 0 15s 10.244.1.23 node01 <none> <none>
nginx-01-799fb6fb65-b6dvg 1/1 Running 0 15s 10.244.1.24 node01 <none> <none>
nginx-01-799fb6fb65-k2dlz 1/1 Running 0 15s 10.244.2.23 node02 <none> <none>
# 创建了一个名为nginx-01的部署(Deployment),使用了nginx:1.14镜像,并将容器的端口设置为80,创建三个副本
[root@master01 ~]# kubectl expose deployment nginx-01 --port=80 --target-port=80 --name=nginx-service -n fql --type=NodePort
service/nginx-service exposed
[root@master01 ~]# kubectl get svc -n fql -o wide
[root@master01 ~]# kubectl get svc -n fql -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
nginx-service NodePort 10.96.128.93 <none> 80:31217/TCP 11s app=nginx-01
[root@master01 ~]# curl -I 10.96.128.93
Server: nginx/1.14.2
6.1 更新 deployment 的版本,并配置暂停 deployment
[root@master01 ~]# kubectl set image deployment nginx-01 nginx=nginx:1.15 -n fql && kubectl rollout pause deployment nginx-01 -n fql
deployment.apps/nginx-01 image updated
deployment.apps/nginx-01 paused
[root@master01 ~]# kubectl rollout status deployment nginx-01 -n fql
Waiting for deployment "nginx-01" rollout to finish: 1 out of 3 new replicas have been updated...
# 更新名为"nginx-01"的部署(Deployment)中的 "nginx" 容器的镜像版本为"nginx:1.15
# 暂停名为"nginx-01"的部署的滚动更新,这意味着在执行这个命令后,将不会继续推进新的副本集,并且当前的副本集将保持不变
6.2 开启另一个窗口查看 pod 信息
监控更新的过程,可以看到已经新增了一个资源,但是并未按照预期的状态去删除一个旧的资源,就是因为使用了 pause 暂停命令
[root@master01 ~]# kubectl get pods -w -n fql
NAME READY STATUS RESTARTS AGE
nginx-01-78cb4c6b78-w6s2l 1/1 Running 0 31s
nginx-01-799fb6fb65-7c29k 1/1 Running 0 2m21s
nginx-01-799fb6fb65-b6dvg 1/1 Running 0 2m21s
nginx-01-799fb6fb65-k2dlz 1/1 Running 0 2m21s
# -w 选项,它会使命令进入监视模式,实时显示资源的变化情况
查看 nginx 版本信息:
[root@master01 ~]# kubectl get pod -n fql -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-01-78cb4c6b78-w6s2l 1/1 Running 0 106s 10.244.2.24 node02 <none> <none>
nginx-01-799fb6fb65-7c29k 1/1 Running 0 3m36s 10.244.1.23 node01 <none> <none>
nginx-01-799fb6fb65-b6dvg 1/1 Running 0 3m36s 10.244.1.24 node01 <none> <none>
nginx-01-799fb6fb65-k2dlz 1/1 Running 0 3m36s 10.244.2.23 node02 <none> <none>
[root@master01 ~]# kubectl get svc -n fql
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-service NodePort 10.96.128.93 <none> 80:31217/TCP 3m12s
[root@master01 ~]# curl -I 10.244.2.24
Server: nginx/1.15.12
[root@master01 ~]# curl -I 10.244.1.23
Server: nginx/1.14.2
[root@master01 ~]# curl -I 10.244.1.24
Server: nginx/1.14.2
[root@master01 ~]# curl -I 10.244.2.23
Server: nginx/1.14.2
6.3 确保更新的 pod 没问题,继续更新
[root@master01 ~]# kubectl rollout resume deployment nginx-01 -n fql
deployment.apps/nginx-01 resumed
6.4 查看最后的更新情况
[root@master01 ~]# kubectl get pod -w -n fql
[root@master01 ~]# kubectl get pod -n fql -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-01-78cb4c6b78-jb5vq 1/1 Running 0 54s 10.244.1.25 node01 <none> <none>
nginx-01-78cb4c6b78-w6s2l 1/1 Running 0 7m27s 10.244.2.24 node02 <none> <none>
nginx-01-78cb4c6b78-xqm9z 1/1 Running 0 52s 10.244.1.26 node01 <none> <none>
6.5 分阶段访问
在金丝雀发布中,将流量分流到新旧版本的这个过程被称为分阶段访问(Staged Access),也可以称为阶段性流量调度(Staged Traffic Shifting)。即将流量逐步引导到新版本的过程,以确保新版本的稳定性和可靠性。
[root@master01 ~]# kubectl set image deployment nginx-01 nginx=nginx:1.16 -n fql && kubectl rollout pause deployment nginx-01 -n fql
[root@master01 ~]# kubectl get pod -n fql
NAME READY STATUS RESTARTS AGE
nginx-01-78cb4c6b78-jb5vq 1/1 Running 0 6h54m
nginx-01-78cb4c6b78-w6s2l 1/1 Running 0 7h1m
nginx-01-78cb4c6b78-xqm9z 1/1 Running 0 6h54m
nginx-01-85c54f54dc-gn67s 1/1 Running 0 36s # 新增实例
默认情况下,访问 server 流量将会负载均衡至4个实例上,新增 server 实现新的实例与旧实例访问分流:
[root@master01 ~]# kubectl expose deployment nginx-01 -n fql --port=80 --target-port=80 --name=new-nginx --type=NodePort
[root@master01 ~]# kubectl get svc -n fql
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
new-nginx NodePort 10.96.255.43 <none> 80:31923/TCP 68s
nginx-service NodePort 10.96.128.93 <none> 80:31217/TCP 7h7m
查看 pod 实例标签名;编辑(查看)位于命名空间 fql 中的名为 new-nginx 的 Service 资源对象,复制文本内容,并创建对应 yaml 文件,修改标签选择器内容:
[root@master01 ~]# kubectl get pod --show-labels -n fql
NAME READY STATUS RESTARTS AGE LABELS
nginx-01-78cb4c6b78-jb5vq 1/1 Running 0 7h9m app=nginx-01,pod-template-hash=78cb4c6b78
nginx-01-78cb4c6b78-w6s2l 1/1 Running 0 7h15m app=nginx-01,pod-template-hash=78cb4c6b78
nginx-01-78cb4c6b78-xqm9z 1/1 Running 0 7h9m app=nginx-01,pod-template-hash=78cb4c6b78
nginx-01-85c54f54dc-gn67s 1/1 Running 0 15m app=nginx-01,pod-template-hash=85c54f54dc
[root@master01 ~]# kubectl edit svc new-nginx -n fql #编辑复制文本
[root@master01 ~]# mkdir yaml;cd yaml
[root@master01 yaml]# vim new-nginx.yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: nginx-01
name: new-nginx
namespace: fql
spec:
clusterIP: 10.96.255.43
clusterIPs:
- 10.96.255.43
externalTrafficPolicy: Cluster
ports:
- nodePort: 31923
port: 80
protocol: TCP
targetPort: 80
selector:
pod-template-hash: 85c54f54dc # 修改为对应标签
sessionAffinity: None
type: NodePort
删除 Kubernetes svc 资源,并根据配置文件创建或更新资源:
[root@master01 yaml]# kubectl delete svc new-nginx -n fql
service "new-nginx" deleted
[root@master01 yaml]# kubectl get svc -n fql
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-service NodePort 10.96.128.93 <none> 80:31217/TCP 7h23m
[root@master01 yaml]# kubectl apply -f new-nginx.yaml -n fql
service/new-nginx created
[root@master01 yaml]# kubectl get svc -n fql
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
new-nginx NodePort 10.96.255.43 <none> 80:31923/TCP 2s
nginx-service NodePort 10.96.128.93 <none> 80:31217/TCP 7h24m
[root@master01 yaml]# kubectl get endpoints new-nginx -n fql
NAME ENDPOINTS AGE
new-nginx 10.244.1.27:80 75s # 对应的后端节点ip为10.244.1.27:80
访问升级版本 pod,查看流量调度是否正确:
[root@master01 yaml]# curl -I 10.244.1.27
Server: nginx/1.16.1
同样的,编辑(查看)位于命名空间 fql 中的名为 nginx-server 的 Service 资源对象,复制文本内容,并创建对应 yaml 文件,修改标签选择器内容:
[root@master01 yaml]# vim nginx-server.yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: nginx-01
name: nginx-service
namespace: fql
spec:
clusterIP: 10.96.128.93
clusterIPs:
- 10.96.128.93
externalTrafficPolicy: Cluster
ports:
- nodePort: 31217
port: 80
protocol: TCP
targetPort: 80
selector:
pod-template-hash: 78cb4c6b78
sessionAffinity: None
type: NodePort
[root@master01 yaml]# kubectl get svc -n fql
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
new-nginx NodePort 10.96.255.43 <none> 80:31923/TCP 10m
nginx-service NodePort 10.96.128.93 <none> 80:31217/TCP 7h35m
[root@master01 yaml]# kubectl delete svc nginx-service -n fql
service "nginx-service" deleted
[root@master01 yaml]# kubectl apply -f nginx-server.yaml -n fql
service/nginx-service created
[root@master01 yaml]# kubectl get svc -n fql
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
new-nginx NodePort 10.96.255.43 <none> 80:31923/TCP 11m
nginx-service NodePort 10.96.128.93 <none> 80:31217/TCP 2s
[root@master01 yaml]# kubectl get endpoints nginx-service -n fql
NAME ENDPOINTS AGE
nginx-service 10.244.1.25:80,10.244.1.26:80,10.244.2.24:80 3m33s
访问旧版本 pod,查看流量调度是否正确:
[root@master01 yaml]# curl 10.96.128.93 -I
Server: nginx/1.15.12
[root@master01 yaml]# curl 10.96.128.93 -I
Server: nginx/1.15.12
[root@master01 yaml]# curl 10.96.128.93 -I
Server: nginx/1.15.12
至此,通过不同 server 对应标签,完成金丝雀发布中,将流量分流到新旧版本的过程。
7. 蓝绿发布
蓝绿发布是一种部署新版本应用程序的策略,旨在减少对用户造成的影响。在蓝绿发布中,两个相同的生产环境并行存在,一个被标记为"蓝色"(Blue),另一个被标记为"绿色"(Green)。
- 蓝色环境:当前稳定的生产环境
- 绿色环境:新版本的生产环境
在初始阶段,所有的用户流量都会指向蓝色环境。当新版本准备就绪时,流量可以逐渐转移到绿色环境。这种逐步迁移流量的方式允许进行实时监控,并在出现问题时快速回滚到蓝色环境。一旦绿色环境被验证为稳定可靠,蓝色环境可以被废弃或者保留作为备份。
8. 发布方式总结
① 滚动发布
按照比例一部分一部分的滚动更新;创建一定比例的 pod,先创建再删除旧的 pod。
② 金丝雀发布(灰度发布)
先更新一部分 pod,然后暂停更新;
安排一小部分的用户流量取访问更新的 pod 来进行测试;
当测试没有问题后再扩大比例,直到全部更新完成为止。
③ 蓝绿发布
蓝:正在运行的稳定版本
绿:新版本的副本
进行新旧版本的切换,用户无感知、业务稳定;但是需要大量的资源、成本高。