[k8s]k8s基础
1 使用minikube创建一个集群
1.1 kubernetes集群
Kubernetes协调一组高度可用的计算机,这些计算机连接在一起以作为一个单一单元工作。k8s提供的抽象可以把容器化的应用部署到集群上,而无需将应用指定到具体的机器上。应用必须容器化。k8s会自动负责应用容器在集群中的分布和调度。
k8s集群包含两种资源:
- 控制平面负责协调整个集群
- Node负责运行应用。
- Node是一个实际的物理机或虚拟机。
- 每个Node有kubelet,负责通控制平面通信以及管理node。
- 每个Node还有负责处理容器运行的工具,例如containerd/CRI-O。
通过控制平面来部署应用,控制平面会负责调度应用容器在node上运行。
可以通过控制平面暴露的kubernetes API和控制平面通信。Node上的kubelet和终端用户都可以通过这种方式同控制平面通信。
1.2 通过minikube创建一个集群
1.2.1 创建一个minikube集群
1 |
|
1.2.2 打开Dashboard
1 |
|
dashboard命令启用dashboard插件并在默认的网页浏览器中打开代理。你可以通过dashboard创建Kubernetes资源,如部署和服务。
通过 --url
参数,可以不自动打开dashboard,而是返回一个url。
默认情况下,dashboard只能在集群内部的虚拟网络中访问,dashboard命令创建了一个临时的代理,使dashboard可以从外部访问。
ctrl+c
可以关闭这个临时代理,但是dashboard还是在集群内部运行,后面可以重新用 dashboard
命令创建代理。
1.2.3 创建一个deployment
deployment会检查pod的状态,并且维护容器的运行,如果容器挂了,会自动重启容器。
用
kubectl create
命令创建一个deployment负责管理pod。pod根据提供的容器镜像运行容器。1
kubectl create deployment hello-node --image=registry.k8s.io/e2e-test-images/agnhost:2.39 -- /agnhost netexec --http-port=8080
查看deployment
1
kubectl get deployments
查看pod
1
kubectl get pods
查看集群事件
1
kubectl get events
查看kubectl配置
1
kubectl config view
查看pod中容器的应用日志
1
kubectl logs hello-node-5f76cf6ccf-br9b5
1.3 创建一个service
默认情况下,pod只能通过集群内部ip地址在集群内部访问。必须将pod作为k8s service暴露出来,才能在外部访问该pod中的容器。
将pod暴露在外部网络中
1
kubectl expose deployment hello-node --type=LoadBalancer --port=8080
--type=LoadBalancer
选项表明希望将服务暴露给集群外部。查看服务
1
kubectl get services
运行下列命令
1
minikube service hello-node
1.4 打开插件(addons)
显示目前支持的插件
1
minikube addons list
打开某个插件
1
minikube addons enable metrics-server
查看安装该插件后,创建的pod和服务
1
kubectl get pod,svc -n kube-system
这条命令查看在kube-system命名空间下的所有pod和service资源的状态。
查看metrics-server的输出
1
kubectl top pods
kubectl top pods
命令用于显示Kubernetes集群中各个Pod的资源使用情况,比如CPU和内存的消耗。top
是kubectl
的一个子命令,用来实时查看集群中资源对象(如Pod或节点)的资源使用情况。pods
指定了查询的对象类型是Pod。这条命令会列出所有命名空间下的Pod及其对应的资源使用情况,除非通过-n
参数指定了特定的命名空间。
为了使
kubectl top pods
命令能够正常工作,集群必须部署了Metric Server。且执行命令的用户需要有访问Metric Server提供的资源指标API的权限。关闭metrics-server插件
1
minikube addons disable metrics-server
1.5清理
清理在集群中创建的资源
1
2kubectl delete service hello-node
kubectl delete deployment hello-node关闭minikube集群
1
minikube stop
2 使用kubectl创建一个deployment
2.1 Kubernetes Deployments
一旦有了一个运行中的Kubernetes集群,就可以在上面部署容器化应用。为此,需要创建一个Kubernetes Deployment。该部署会指示Kubernetes如何创建和更新应用实例。创建部署后,Kubernetes控制平面会调度该部署中包含的应用实例在集群的各个节点上运行。
一旦应用实例被创建,Kubernetes部署控制器会持续监控这些实例。如果托管实例的节点发生故障或被删除,部署控制器会用集群中另一个节点上的实例替换该实例。这提供了一种自我修复机制,以应对机器故障或维护。
2.2 在k8s上部署应用
可以使用Kubernetes命令行界面kubectl来创建和管理deployment。Kubectl利用Kubernetes API与集群进行交互。
当创建一个deployment时,需要指定应用的容器镜像和希望运行的副本数量。也可以后续通过更新deployment来更改这些信息。
2.3 kubectl基础
kubectl命令通用格式:kubectl action resource
这会在指定的资源(node,deployment…)上执行指定的操作(create, describe, delete…)。可以用 --help
命令来查看可能的参数(kubectl get nodes --help
)。
2.4 部署一个应用
通过以下命令部署应用。需要指明deployment的名字以及应用镜像的位置。
1 |
|
这个命令会进行以下几个操作:
- 查找合适的node来运行应用
- 调度应用在该node上运行
- 配置集群,当需要的时候重新调度实例运行
使用 kubectl get deployments
命令来查看所有的deployment。
2.5 查看应用
在Kubernetes内部运行的Pod位于一个私有的、隔离的网络中。默认情况下,它们只能被同一个Kubernetes集群内的其他Pod和服务看到,而不能从外部网络访问。当使用kubectl时,是通过API端点与应用程序进行交互的。
kubectl proxy命令可以创建一个代理,将通信转发到集群范围的私有网络中。代理可以通过按下Control+C终止,并且在运行时不会显示任何输出。
需要打开第二个终端窗口来运行这个代理。
1 |
|
现在已经在主机(终端)和Kubernetes集群之间建立了连接。这个代理允许从这些终端直接访问API。
可以通过代理端点查看所有这些API。例如,可以使用curl命令直接通过API查询版本:
1 |
|
API服务器会根据Pod的名称自动为每个Pod创建一个端点,这些端点也可以通过代理访问。
首先,需要获取Pod的名称
1 |
|
你可以通过代理API访问Pod,运行以下命令:
1 |
|
3 查看Pods和Nodes的信息
3.1 Pods
当创建一个deployment时,Kubernetes创建了一个Pod来承载应用实例。Pod是Kubernetes的一种抽象,代表了一组一个或多个应用程序容器(如Docker容器),以及这些容器共享的一些资源。这些资源包括:
- 共享存储,以volume的形式提供
- 网络,提供唯一的集群IP地址
- 运行每个容器的信息,例如容器镜像版本或要使用的特定端口
Pod模型化了一个应用特定的“逻辑主机”,它可以包含不同的应用程序容器,这些容器之间的耦合相对紧密。Pod中的容器共享同一个IP地址和端口空间,总是共同位于一处并一同调度,并在同一个节点上以共享的上下文运行。
在Kubernetes平台上,Pod是最小的部署单元。当创建一个deployment时,该deployment会创建包含容器的Pod(而不是直接创建容器)。每个Pod都绑定到它被调度的node上,并一直留在那里直到终止(根据重启策略)或删除。如果节点发生故障,相同的Pod会被调度到集群中其他可用的节点上。这样可以确保应用的高可用性和可靠性。
3.2 Nodes
Pod运行在一个Node上。Node是Kubernetes中的工作机器,可以是虚拟机也可以是物理机。每个Node都由控制平面管理。一个Node可以运行多个Pod,Kubernetes控制平面会根据node的可用资源在集群的Nodes之间调度这些Pod。
每个Kubernetes Node至少运行以下组件:
- Kubelet:是负责Kubernetes控制平面与Node之间通信的进程;它管理运行在该机器上的Pod和容器。
- 容器运行时(如Docker):负责从注册表中拉取容器镜像、解包容器并运行应用程序。
只有容器之间是高度耦合的并且需要共享资源(硬盘)的时候,它们才应该被规划到同一个pod中。
3.3 Troubleshooting with kubectl
最常见的操作可以通过以下kubectl命令完成:
kubectl get:列出资源。例如,可以用来列出Pods、Services等资源。
1
kubectl get pods
kubectl describe:显示资源的详细信息。这对于获取有关特定资源(如Pod,node,deployment)的深入信息非常有用,包括状态、事件等。
1
kubectl describe pod <pod-name>
kubectl logs:从Pod中的容器打印日志。这对于调试运行中的应用和检查错误特别有用。
1
kubectl logs <pod-name>
kubectl exec:在Pod中的容器上执行命令。这对于进入容器内部进行调试或直接操作非常有用。
1
kubectl exec -it <pod-name> -- /bin/sh
3.3.1 查看容器的日志
应用程序通常会将其标准输出发送到容器内的日志中。可以使用kubectl logs
命令检索这些日志:
1 |
|
注意:当在Pod中只有一个容器的时候,无需指定容器名称。如果Pod中有多个容器,需要使用-c
选项指定容器名称来查看特定容器的日志。
查看特定Pod中所有容器的名称
1 |
|
在输出的信息中,找到 Containers:
部分,这里列出了该Pod中所有容器的名称及其相关信息。
在输出结果中,会看到类似如下的部分:
1 |
|
这里的 container-one
和 container-two
就是Pod中容器的名称。
3.3.2 在容器中执行命令
可以直接在Pod启动并运行后,在容器中执行命令。
使用exec
子命令,并将Pod的名称作为参数。让我们列出环境变量:
1 |
|
在Pod的容器中启动一个bash会话:
1 |
|
已经打开了运行应用的容器控制台。应用的源代码位于server.js
文件中:
1 |
|
可以通过运行以下curl命令来检查应用程序是否已启动并正在运行:
1 |
|
输入exit
来关闭与容器的连接
1 |
|
这样就可以退出bash会话,返回到本地终端。
4 通过service来将应用暴露给外部网络
4.1 kubernetes services
在Kubernetes中,Pod是临时的,并且有其生命周期。当一个工作节点失效时,运行在其上的Pod也会丢失。这时,ReplicaSet可以根据需要动态地通过创建新的Pod来使集群回到期望的状态,以保持应用程序的持续运行。例如,考虑一个有3个副本的图像处理后端应用。这些副本是可以互换的;前端系统不应该关心后端副本的具体情况,甚至不需要知道某个Pod丢失并被重新创建的情况。然而,每个Pod在Kubernetes集群中都有一个唯一的IP地址,即使是位于同一Node上的Pod也是如此,因此需要一种方法自动协调Pod之间的变化,以确保你的应用程序继续正常运行。
Service是一个抽象概念,它定义了一组逻辑上的Pod以及访问它们的策略。Service使得互相依赖的Pod之间可以松散耦合。Service可以通过YAML或JSON进行定义。
目标Pod集:通常由label selector决定(但在某些情况下,你可能希望创建一个没有选择器的Service)。
IP暴露问题:尽管每个Pod都有一个唯一的IP地址,但如果没有Service,这些IP地址不会暴露到集群外部。Service允许你的应用程序接收流量。
Service类型
根据你在Service的spec中指定的类型,Service可以通过不同的方式暴露:
ClusterIP(默认):在集群内部IP上暴露Service。这种类型使得Service只能从集群内部访问。
NodePort:通过NAT在集群中每个选定node的相同端口上暴露Service。这使得你可以使用
<NodeIP>:<NodePort>
从集群外部访问Service。它是ClusterIP的超集。LoadBalancer:在当前云环境中创建一个外部负载均衡器(如果支持),并为Service分配一个固定的外部IP。它是NodePort的超集。
ExternalName:将Service映射到externalName字段的内容(如foo.bar.example.com)。不设置任何形式的代理。
其他注意事项
有时,你可能会遇到一些不需要在Service的spec中定义选择器的用例。一个没有选择器的Service也不会创建相应的Endpoints对象。这允许用户手动将Service映射到特定的端点。另一种可能是严格使用type: ExternalName
的情况。
4.2 service和labels
在Kubernetes中,Service用于将流量路由到一组Pod。依赖Pod之间的发现和路由(例如应用中的前端和后端组件)是由Kubernetes Services处理的。
Service如何匹配Pod
Service通过使用标签(labels)和选择器(selectors)来匹配一组Pod。标签和选择器是Kubernetes中的一种分组原语,允许对对象进行逻辑操作。
标签(Labels):标签是附加到对象上的key/values对,可以以多种方式使用。例如:
- 为开发、测试和生产环境指定对象。
- 嵌入版本标签。
- 使用tags对对象进行分类。
选择器(Selectors):选择器用于定义哪些带有特定标签的Pod应属于该Service。通过这种方式,Service可以动态地适应集群的变化,如Pod的增加或删除。
4.3 实例
step 1:创建一个service
1 |
|
使用该命令创建一个NodePort类型的服务,该服务向外部暴露端口。
使用 kubectl describe services/kubernete-bootcamp
命令来查看详细信息。
可以看到向外开放的端口是30247.
接下来,可以使用 curl http:"(minikube ip)":30247
来使用服务。
注意,在windows下使用docker desktop的时候,需要配置一个minikube tunnel。通过tunnel来进行转发。
Step 2:使用Labels
deployment自动为pod分配了一个标签,可以通过 describe deployment
命令来查看。
在get命令中使用-l参数指明标签来选择相应的pod和service
1 |
|
使用label命令来为对象指明新的标签。
1 |
|
Step 3:删除service
1 |
|
5 运行应用的多个实例
scaling是通过修改deployment中replica的个数来实现的。
在创建deployment的时候可以通过 --replicas
参数来创建多个实例。
5.1 Scaling概述
扩展Deployment将确保创建新的Pod,并将其调度到具有可用资源的节点上。通过扩展,可以增加Pod的数量以达到新的期望状态。Kubernetes还支持Pod的自动扩展。此外,将Pod数量扩展为零也是可行的,这将终止指定Deployment的所有Pod。
运行应用程序的多个实例需要一种方式来分配流量给所有的实例。Kubernetes中的Service具备集成的负载均衡器,能够将网络流量分配给暴露的Deployment中的所有Pod。Service会持续监控运行中的Pod,确保流量仅发送到可用的Pod。
当你有多个应用程序实例在运行时,你可以执行滚动更新(Rolling Updates)而不会造成停机。滚动更新允许你逐步替换旧的Pod并启动新的Pod,确保服务的连续性。
5.2 查看ReplicaSet
要查看由Deployment创建的ReplicaSet,可以运行以下命令:
1 |
|
ReplicaSet的名字总是格式为 [DEPLOYMENT-NAME]-[RANDOM-STRING]
。这里的随机字符串是随机生成的,并使用pod-template-hash
作为种子。
在输出中,有两个重要的列需要注意:
- DESIRED:显示定义的期望的应用程序副本数量。这是在创建Deployment时指定的期望状态。
- CURRENT:显示当前实际运行的副本数量。
5.3 扩展Deployment
要手动扩展Deployment,你可以使用kubectl scale
命令。例如,要将一个名为web-app
的Deployment扩展到5个副本:
1 |
|
这条命令将使Kubernetes创建足够的Pod以达到指定的副本数(在这个例子中是5个)。如果当前已经有5个或更多Pod在运行,Kubernetes会相应地减少或增加Pod的数量。
5.4 自动扩展(Horizontal Pod Autoscaler)
虽然手动扩展适用于已知的工作负载,但Kubernetes也支持基于CPU利用率等指标的自动扩展(Horizontal Pod Autoscaler)。你可以在创建Deployment时配置自动扩展策略,或者稍后添加。例如,以下命令设置了一个Deployment web-app
的自动扩展策略,使其副本数在1到10之间变化,根据平均CPU使用率调整:
1 |
|
这意味着当平均CPU使用率达到80%时,Kubernetes会自动增加Pod的数量,最多不超过10个;当负载下降时,它也会减少Pod的数量,最少保持1个Pod运行。
6 滚动更新
6.1 更新应用
滚动更新允许在不造成停机的情况下进行部署更新,其工作原理是逐步用新Pod替换当前的Pod。新Pod被调度到有可用资源的节点上,Kubernetes会等待这些新Pod启动后再移除旧的Pod。
滚动更新的必要条件:应用程序在集群中有多个运行实例。
默认情况下,更新过程中不可用的最大Pod数量和可以创建的新Pod最大数量均为1。这两个选项都可以配置为具体的数字或比例(的Pod)。在Kubernetes中,更新是具有版本控制的,任何部署更新都可以回滚到之前的(稳定)版本。
6.2 滚动更新概述
类似于应用程序扩展,如果一个部署被公开暴露,那么在更新期间,服务将仅向可用的Pod分发流量。
滚动更新允许执行以下操作:
- 通过容器镜像更新将应用程序从一个环境升级到另一个环境
- 回滚到之前的版本
- 实现应用的持续集成和持续交付,并且达到零停机时间
6.3 更新应用版本
首先查看更新前的镜像版本(kubectl describe pods
)
要将应用程序的镜像更新到第2版,可以使用set image
子命令,随后跟上deployment名称和新的镜像版本:
1 |
|
此命令通知deployment使用新版本的镜像进行应用更新,并启动了一个滚动更新。可以通过get pods
子命令检查新Pod的状态,并查看旧Pod正在终止:
1 |
|
6.4 验证更新
1 |
|
每次运行curl命令时,都会访问到不同的Pod。请注意,现在所有Pod都在运行最新版本(v2)。
也可以通过运行rollout status
子命令来确认更新状态:
1 |
|
要查看应用程序当前的镜像版本,可以运行describe pods
子命令:
1 |
|
在输出的镜像字段中,确认正在运行的是最新的镜像版本(v2)。
6.5 回滚更新
让我们执行另一次更新,并尝试部署一个标记为v10的镜像:
1 |
|
使用get deployments
查看部署的状态:
1 |
|
注意,输出中没有列出期望的可用Pod数量。运行get pods
子命令列出所有Pod:
1 |
|
注意到一些Pod的状态为ImagePullBackOff。
为了更深入地了解问题,运行describe pods
子命令:
1 |
|
在受影响Pod的输出事件部分中,注意到v10镜像版本在仓库中不存在。
要回滚部署到最后一个正常工作的版本,使用rollout undo
子命令:
1 |
|
rollout undo
命令将部署恢复到之前的已知状态(即镜像的v2版本)。更新是版本化的,可以回滚到Deployment的任何之前已知的状态。
再次使用get pods
子命令列出Pod:
1 |
|
要检查正在运行的Pod上部署的镜像,使用describe pods
子命令:
1 |
|
现在,Deployment再次使用应用程序的一个稳定版本(v2)。回滚成功。
记得清理本地集群:
1 |
|