准备

需要的三个东西:minikube,docker,kubectl

  1. minikube:minikube支持一键部署kubernetes集群,用于单机测试和日常开发,minikube安装可参考官网:https://minikube.sigs.k8s.io/docs/start/,参照官网根据不同的系统到不同的地址下载对应的安装包即可,这个网站还有minikube相关知识
    关于使用minikube部署kubernetes的使用可以参考kubernetes官网:https://kubernetes.io/zh-cn/docs/tutorials/hello-minikube/
  2. docker:docker是Kubernetes支持的一种容器运行时(container runtime),用于创建和管理容器,需要手动下载,具体可以参考:阿里云docker-ce镜像
  3. kubectl:kubectl是kubenetes命令行工具,通过kubectl可以部署和管理应用,查看各种资源,创建,删除和更新组件,官网安装参考:kubectl安装参考

启动

docker

启动

首先,启动docker,这里启动时遇到一个问题:Error creating default “bridge” network: Failed to program NAT chain: INVALID_ZONE: docker,原因是因为版本大于等于 20.10.0的docker会自动创建了一个名为docker的 firewalld zone,需要将docker0虚拟网卡加入到这个zone才能正常启动,一般情况下docker0网卡应该默认就在docker zone下面

创建用户

minikube不能直接在root用户下启动,所以启动minikube的用户需要加入到docker用户组才能启动、操作docker

1
2
3
4
5
6
#创建docker用户组,一般情况下,安装docker时,会自动创建docker用户组
sudo groupadd docker
#普通用户加入docker用户组
sudo usermod -aG docker ${用户名}
#重启docker
sudo systemctl restart docker

minikube

启动

minikube启动命令,这里启动时遇到一个问题,minikube内部所需的镜像等无法正常下载,本地环境是虚拟机,为虚拟机的ens33网卡配置dns后,下载正常

1
minikube start --driver="docker" --registry-mirror="https://kn0t2bca.mirror.aliyuncs.com"
  1. –driver:指定容器运行时
  2. –registry-mirror:镜像地址,minikube拉取镜像时的地址,也就是minikube内部docker的镜像地址,可以进入minikube后执行docrer info确认
    如果需要更换的话,必须先执行minikube delete删除当前minikube环境(所有deployment、pod等都没了),在执行start命令,还没有找到其他办法

进入minikube

minikube的启动实际上是创建了一个docker容器,使用docker容器作为运行kubernetes的主机

进入方法包括两种,一种是通过docker exec(进入后是root用户),一种是通过minikube ssh命令(进入后是docker用户)

可以到容器内部,检查相关内容,例如网络,在外网环境下,minikube必须要能够访问外网才能在首次启动时正常下载需要的镜像并且在之后的使用中正常拉取镜像。后面所有pod管理的容器实际上也是minikube容器下创建的

仪表板

minikube启动后可以通过一个命令打开一个浏览器或输出一个url,可以访问kubernetes集群控制台

1
minikube dashboard --url//加上--url会输出一个url,不加的话,系统会尝试打开一个浏览器自动访问

这个命令的作用是展示kubernetes的dashboard组件提供的地址,但是minikube默认只代理127.0.0.1的流量,这时候可以使用kubectl proxy命令,kubectl proxy将本地流量代理到Kubernetes集群的API Server,我们如果需要代理其他网卡的流量,可以单独执行kubectl proxy命令,具体路径参考minikube dashboard –url输出的路径,只是需要注意ip和端口的变化

1
kubectl proxy --port=8080 --address='192.168.255.100' --accept-hosts='^.*' &
  1. –port=8080:代理端口为8080
  2. –address=’192.168.255.100’:代理的ip,配合–port参数,可以理解为将访问192.168.255.100:8080的请求转发到Kubernetes集群
  3. –accept-hosts=’^.*’ &:接受哪些主机的访问请求,这里的值代表全部

相关内容

这里了解Deployment、Endpoint、Pod、Service等知识

Deployment

Kubernetes Deployment 是一种用于管理容器化应用实例的控制器,它确保在集群中按照用户定义的规格(如副本数量、镜像版本等)持续运行并能自动进行滚动更新与恢复。一般情况下,在命令当中,deployment可以被简写为deploy

相关命令

创建deployment命令,除了create通过命令创建,还可以通过apply使用yaml文件创建deployment,这里使用create命令示例

1
kubectl create deploy hello-node --image=nginx --replicas=3
  1. hello-node:deployment的名称
  2. –image=nginx:使用nginx的镜像
  3. –replicas=3:启动三个副本(Pod),并且确保Deployment应该始终保持 3 个副本(Pod)的数量在线,当有 Pod 故障时,Kubernetes 会自动创建新的 Pod 来替换故障的 Pod,以保持副本数目的稳定

deployment创建完后也可以通过scale修改副本数

1
kubectl scale deploy hello-node --replicas=2
  1. hello-node:deployment的名称
  2. –replicas=2:修改副本数

deployment创建后可通过get deployment查看所有deployment

1
kubectl get deploy

滚动更新

滚动更新是deployment的功能之一,在使用kubectl apply -f命令时,如果deployment已存在并且内容发生了变化,则会重新创建一个ReplicaSet并滚动创建新的pod(即等新的pod启动后才会关闭旧的pod,保证任何时候都能正常访问),需要注意通过create命令,无法实现滚动更新

滚动恢复

在进行上面的滚动更新操作后,旧的ReplicaSet并不会再使用,它所管理的pod也会被陆续删除,但是旧的ReplicaSet本身会被保留,一个ReplicaSet可以代表一个版本,可以通过kubectl rollout history查看版本列表

1
kubectl rollout history deployment <deployment-name> --revision=3 #--revision:可选,代表查看具体的版本

可通过kubectl rollout undo命令滚动回退版本(保证任意时刻都有pod在运行)

1
kubectl rollout undo deployment <deployment-name> --to-revision=3 #--to-revision:可选,代表回退到指定版本

ReplicaSet

ReplicaSet是Kubernetes中用于确保指定数量的Pod副本按照同一模板运行并保持一致性的控制器,它具备自动扩缩容和自我修复能力,确保Pod服务的高可用性和稳定性。它的名称通常就是deployment+随机字符串。在创建deployment时,ReplicaSet会被自动创建。一般情况下,命令中的ReplicaSet可以被简写为rs

相关命令

可通过get replicaset获取所有replicaset

1
kubectl get rs

Pod

Pod是Kubernetes中部署和管理容器化应用的基本单位,它封装了一个或多个紧密相关的容器,这些容器共享存储卷、网络命名空间和IPC(进程间通信),共同组成一个运行环境。Pod强调了容器间的协同工作,确保这些容器一起调度、一起运行,并且具有唯一的IP地址和网络标识,以实现高效的微服务架构部署与管理。

相关命令

可通过get pods获取所有pod

1
kubectl get pods

可通过describe 查看pod日志

1
kubectl describe pod <pod-name>

可通过exec命令进入pod创建的容器

1
2
kubectl exec -it <pod-name> -- bash//pod只有一个容器的情况下
kubectl exec -it <pod-name> [-c <container-name>] -- bash//pod多个容器的情况下

访问pod

通过dashboard访问

pod可以通过dashboard访问,举个例子

http://192.168.255.100:8080/api/v1/namespaces/default/pods/hello-node-86c8975888-rqqms:80/proxy/

例子中的hello-node-86c8975888-rqqms代表容器,80代表访问容器的端口,后面的/proxy/是必须的,综合起来hello-node-86c8975888-rqqms:80/proxy/相当于访问容器的80端口,如果需要访问具体资源,则为hello-node-86c8975888-rqqms:80/proxy/+资源路径

通过pod ip访问

这种方式仅支持在pod内部访问,如下

Service

Kubernetes Service是一个抽象层,它定义了一个稳定的网络入口点,通过标签选择器将流量路由到后端的一组Pod实例上,并提供负载均衡和服务发现机制。简单来说,Service是连接和管理Pod间通信以及对外暴露服务的核心组件。service拥有很多功能,例如:服务发现、负载均衡。一般命令中的service可以被简写为svc

相关命令

可通过kubectl expose deployment发布service

1
kubectl expose deployment hello-node --type=LoadBalancer --port=80 --target-port=8080
  1. deployment:这里指为指定的deployment创建service,但是不但可以为deployment创建service,还可以为replicaset、pod等创建service
  2. hello-node:deployment的名字,如果是为replicaset、pod创建service,那么就是replicaset、pod的名称
  3. –type=LoadBalancer:type决定了服务如何路由流量到后端Pod,包括
    1. ClusterIP (默认类型): 创建一个仅在集群内部可以访问的服务,由集群内其他服务或Pod通过内部IP地址进行访问。
    2. NodePort:在ClusterIP的基础上,还会在每个Node上开放一个特定端口(30000-32767范围内的随机端口或者指定端口),允许外部客户端通过这个端口直接访问到服务。这意味着集群外部可以通过任何节点的该端口访问服务。这里的Node在minikube环境下可以理解为minikube容器,普通情况下就是运行kubernetes的节点
    3. LoadBalancer: 适用于云环境,在NodePort的基础上,会在云提供商层面创建一个负载均衡器,将外部流量转发到Service。负载均衡器会分配一个公网IP地址,使得外部网络可以直接访问到服务。如果条件允许,可通过外网ip访问
    4. ExternalName: 将Service映射到DNS名称,不创建集群内部的Endpoints。当集群需要引用集群外的服务时,这种类型非常有用
    5. Headless Service(无头服务): 不为Service分配Cluster IP,而是创建没有代理的Endpoints资源对象,通常与StatefulSet配合使用,直接通过Pod的DNS名称进行通信
  4. –port:service监听端口
  5. –target-port=8080:目标端口,结合配置–port可以理解为发起到service的80端口的请求会被转发到pod内部的8080端口

通过kubectl get services命令查看service

1
kubectl get services

访问service

在上图的hello-node服务中,type=LoadBalancer代表使用LoadBalancer模式路由,cluster-ip=10.100.105.87是为Service创建的集群IP

通过dashboard访问

service和pod一样,也可以通过集群api访问,举个例子

http://192.168.255.100:8080/api/v1/namespaces/default/services/hello-node:80/proxy/

格式和pod类似,其中services对应上面例子的pods,代表类型,hello-node是service的名字,80是访问service的端口,即创建service是配置的–port

通过service生成的集群ip访问

上面的提到ClusterIP、NodePort、LoadBalancer模式下,都会为Service生成一个集群ip,这个ip只能在pod内部访问,并且在pod内部还可以通过Service的名称(可以理解为域名,CoreDNS组件的功能)访问,名称对应的ip地址就是Servicd的集群ip地址

通过静态端口访问

上面提到的NodePort、LoadBalancer模式下,会为Node创建一个静态端口,可以在集群外通过这个静态端口访问Service,在minikube环境下,minikube容器就是一个Node,所以可以通过minikube的ip加上静态端口访问Service,下图的是minikube容器的ip,即kubernetes Node的ip

服务发现

kubernetes的服务发现功能就是通过service实现的,kubernetes会根据servcie的名称建立一个DNS记录,而kubelet 在启动 Pod 时也会配置 Pod 中的 resolv.conf 文件,指向集群中的 DNS 服务器,所以在pod内部可以通过http://<service的名称>:的方式访问service

负载均衡

service默认提供了基本的四层(TCP/UDP)负载均衡能力,该能力主要通过 kube-proxy 组件实现,并且基于 IP 地址和端口进行分发流量,使用一定的策略将请求分发到后端 Pod。这里提到的四层(TCP/UDP)负载均衡能力,可以理解为nginx的stream模块,而nginx的http模块,可以对具体http路径进行代理负载,实现七层(HTTP/HTTPS)负载均衡,service在不借助其他工具的情况下无法实现类似nginx的http模块的功能

Endpoint

Endpoint(端点)是 Service 与 Pod 实例之间的逻辑连接。一个 Endpoint 对象代表了 Pod 的 IP 地址和端口号的集合,这些 Pod 为同一个 Service 提供服务,Service 通过 Cluster IP 和端口提供统一的服务入口,而实际的请求会被路由到这些已经记录在 Endpoints 中的 Pod 实例上。这样就实现了对后端应用实例的负载均衡和服务发现。Endpoint会根据pod的状态自动更新,确保Service始终指向可用的pod实例。在Kubernetes v1.17及之后的版本,引入了EndpointSlices用于代替Endpoint。一般命令中的endpoints可以被简写为ep

相关命令

可通过get endpoints获取端点

1
kubectl get endpoints

探针

介绍

探针在Kubernetes中的作用是对Pod进行健康检查,一个额外的知识,容器在创建时镜像执行的第一个命令或者应用程序会作为容器内的主进程(也称为PID 1)。这个主进程的生命周期直接决定了容器的生命周期,也就是说如果一个运行nginx的docker,当nginx的进程死掉之后,docker容器也就停止了,这时候pod会直接重启,即pod会删除原容器并通过镜像重新运行一个容器

Kubernetes包含三种探针,三种探针检查时机以及检测失败后的动作有所不同

  1. 存活探针(Liveness Probe): 目的是确定容器内的主应用程序是否还在正常运行。如果存活探针检测失败,Kubernetes会认为容器内的主进程已死锁或不可用,进而根据Pod的重启策略重启容器。
  2. 就绪探针(Readiness Probe): 用于决定容器是否准备好开始接收请求。如果就绪探针检测失败,Kubernetes会从服务负载均衡列表中移除该容器,直到就绪探针再次成功,这意味着容器所在Pod在此期间不会接受新的流量。这里并不会重启pod。
  3. 启动探针(Startup Probe): 判断容器内的应用是否已经正确启动。如果提供了启动探针,Kubernetes会在应用完全启动之前忽略其他的存活探针和就绪探针。只有当启动探针成功后,才会开始执行其他探针。如果启动探针失败,Kubernetes会杀死容器并依据重启策略进行重启。

这三种探针都可以通过以下方式执行检测:

  • exec: 执行容器内部的特定命令,根据命令的退出状态码判断探针的成功与否。
  • tcpSocket: 尝试通过TCP连接到容器的指定端口,如果连接成功则认为探针成功。
  • httpGet: 发起HTTP GET请求到容器的服务端点,根据响应的状态码判断探针的成功与否。

示例

下面是Liveness Probe的TcpSocket检测方式的示例,其余两个探针只需要示例中的改livenessProbe成readinessProbe或者startupProbe即可,如需更改检测方式,只需将配置中tcpSocket改为exec或者httpGet即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
apiVersion: apps/v1 #用来指定资源对象使用的API版本
kind: Deployment #指定资源对象
metadata: #创建的资源对象属性
name: demo #创建的资源对象名称
spec: #定义Deployment对象的具体配置和期望状态
replicas: 1 #pod(副本)数量
selector: #选择器配置,这里选择器的作用是匹配到的pod归于这个deployment管理
matchLabels: #通过labels选择匹配
app: demo #匹配labels属性包含app: demo的pod
template: #模板,即pod相关配置
metadata: #定义pod属性
labels: #定义pod的lables属性
app: demo #定义pod的labels属性为app: demo,这里配置需与上面的一样,这样才能将创建的pod归于deployment管理
spec: #定义pod对象的具体配置和期望状态
containers: #pod下容器相关配置
- name: my-container #容器名称
image: demo #容器使用的镜像
imagePullPolicy: IfNotPresent #镜像拉取策略,IfNotPresent指只要本地有这个镜像,则不拉取,不考虑版本,而Always配置会考虑版本,如果本地镜像的版本是latest,则会拉取,Never配置只从本地获取,不会拉取,如果本地没有,则报错
livenessProbe: #livenessProbe探针相干配置
tcpSocket: #livenessProbe配置通过tcpSocket对容器进行检测
port: 8081 #配置tcpSocket检测的端口
initialDelaySeconds: 1 #容器启动后多久开始进行检测
periodSeconds: 5 #检测频率,隔多久检测一次
timeoutSeconds: 1 #探针执行检测请求后,等待响应的超时时间
successThreshold: 1 #探针检测失败后认为成功的最小连接成功次数,默认为1s,在liveness探针中必须为1s,最小为1s
failureThreshold: 1 #探测失败的重试次数,重试一定次数后将认为失败

测试

关于具体的容器,我们使用Java编写一个程序用于检测是否有进行tcp检测

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
@RestController
public class TestController implements InitializingBean {

private ServerSocket serverSocket;

@GetMapping("/closeSocket")
public String closeSocket(){
try {
serverSocket.close();
} catch (IOException e) {
return "false";
}
return "true";
}

@Override
public void afterPropertiesSet() throws Exception {
try {
serverSocket = new ServerSocket(8081);
new Thread(() -> {
while(true){
Socket accept;
try {
accept = serverSocket.accept();
} catch (IOException e) {
throw new RuntimeException(e);
}
System.out.println(DateTime.now() + ":" + accept.getRemoteSocketAddress());
}
}).start();
} catch (IOException e) {
throw new RuntimeException();
}
}
}

这段代码打开一个端口为8081的ServerSocket,用于kubernetes做检测,并且提供一个方法用于关闭此ServerSocket,用于测试kubernetes是否会重启pod

可以看到每隔5秒,程序就会建立一个tcp连接,证明kubernetes探针已经生效了

我们调用closeSocket接口关闭serverSocket,看一下是否会pod是否会重启

查看pod的事件,发现探针检测到了端口关闭,并且pod进行了重启

查看容器日志,发现重新运行了


本站总访问量:次本站总访问数:人
本站由 Peng Tong 使用 Stellar 1.29.1 主题创建。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。