Service存在的意义
Kubernetes中的Service是一种网络抽象,用于将一组Pod暴露给其他组件,例如其他Pod或外部用户。Service可以作为一个负载均衡器,为一组Pod提供单一的IP地址和DNS名称,并通过选择器来将流量路由到这些Pod。
Services的存在有以下几个意义:
- 透明的服务发现: Kubernetes使用Service作为一种透明的服务发现机制。使用Service可以将Pod隐藏在后面,这样其他组件可以使用Service的DNS名称来访问它们,而不需要知道Pod的实际IP地址和端口号。
- 负载均衡: Service可以将流量路由到一组Pod上,并使用标签选择器将流量均匀地分配给这些Pod。这使得可以轻松地进行水平扩展,以满足不断增长的负载。
- 稳定的IP地址: Kubernetes为每个Service分配一个稳定的IP地址,这个IP地址与Pod的生命周期无关。这意味着可以在Pod启动和停止时保持稳定的服务地址,并且无需手动更改任何配置。
- 外部访问: 通过将Service类型设置为NodePort或LoadBalancer,可以将Service暴露给外部用户或外部负载均衡器。这使得可以轻松地将Kubernetes集群与外部服务和用户集成。
总之,Service是Kubernetes中非常重要的一部分,可以提供透明的服务发现、负载均衡、稳定的IP地址和外部访问。在实际生产环境中,使用Service是构建可靠和可扩展应用程序的关键。
Pod、Service、Label的关系
在Kubernetes中,Pod是最小的可部署单元,它是由一个或多个容器组成的。Pod提供了一个运行环境,其中包含应用程序所需的资源,如存储、网络和命名空间。
Service是Kubernetes中的一种抽象,用于定义一组Pod,这些Pod执行相同的任务,并且可以通过Service的IP地址和端口号进行访问。Service允许应用程序通过固定的IP和端口号进行访问,而不必考虑后端Pod的IP和端口号。
在Kubernetes中,Pod和Service之间有一种紧密的关系。Service使用标签选择器来确定哪些Pod应该成为它的后端。一旦Service选择了一组Pod,它将为这些Pod分配一个固定的IP和端口号,这些IP和端口号将用于访问这些Pod。
当Pod被创建或删除时,Service会自动更新它的后端列表。这意味着当Pod被添加到Service的后端时,它们将自动成为Service的一部分,并且可以通过Service的IP和端口号进行访问。同样地,当Pod被删除时,它们将自动从Service的后端列表中删除,这样访问它们的请求就不会被发送到已经不存在的Pod上。
因此,Pod和Service之间的关系是非常紧密的,Service为一组Pod提供了一个稳定的网络地址,并且自动更新它的后端列表以确保访问这些Pod时的高可用性和可靠性。
在Kubernetes中,Pod、Service和标签之间有着密切的关系。标签(Label)是Kubernetes中的一种机制,它允许你为对象添加任意的元数据,例如版本、环境、用途等等。
Pod可以使用标签进行分类和分组,通过给Pod打上特定的标签,可以方便地对它们进行选择和管理。同样地,Service也可以使用标签选择器来选择具有特定标签的Pod作为后端。标签可以被应用于任何Kubernetes对象,包括Pod、Service、ReplicaSet等等。
当创建一个Service时,可以使用标签选择器来指定Service所选取的Pod的标签。例如,可以通过以下方式创建一个Service,它将选择所有标有app=goweb-demo的Pod作为它的后端:
goweb-demo-v1.yaml
apiVersion: v1 kind: Service metadata: name: goweb-demo spec: ports: - port: 80 protocol: TCP targetPort: 8090 selector: app: goweb-demo
在这个例子中,Service使用selector字段来选择具有app=goweb-demo标签的Pod作为它的后端。这意味着只有那些标记为app=goweb-demo的Pod才能被Service访问。
标签是Kubernetes中非常重要的一个概念,它使得对Pod和Service的选择和管理变得更加灵活和高效。通过使用标签,可以轻松地对应用程序的不同版本、环境和用途进行分类和分组,并根据需要创建相应的Pod和Service来满足应用程序的需求。
Service的访问类型
Kubernetes中的Service对象可以指定不同的访问类型,以便在集群内和集群外提供不同级别的访问。 下面是Kubernetes中Service的三种访问类型:
- ClusterIP:默认的访问类型,将创建一个虚拟IP地址,代表一组后端Pod。只能从集群内部访问该Service,外部无法访问。
- NodePort:将在每个Node上公开一个端口,并将该端口重定向到Service。可以通过Node的IP地址和该端口访问该Service。可以从集群外部访问该Service,但需要在防火墙中打开该端口。
- LoadBalancer:将在外部创建一个负载均衡器,并将流量路由到Service。负载均衡器可以将流量路由到多个后端Pod,以提高可用性和性能。需要使用外部负载均衡器的云平台支持,例如AWS ELB或GCP GCLB。
另外,还有一种名为ExternalName的访问类型,可以将Service映射到集群外部的DNS名称,而不是集群内部的Pod。该访问类型通常用于将Service映射到外部服务,例如数据库或API网关。
可以使用kubectl命令行或YAML文件来指定Service的访问类型和其他配置。例如,在YAML文件中,可以将Service的类型指定为type: ClusterIP、type: NodePort或type: LoadBalancer,具体取决于需要提供的访问级别。
实战开撸:案例1
- 准备Deployment yaml配置文件
kubectl create deployment goweb-demo --image=192.168.11.247/web-demo/goweb-demo:20221229v3 --replicas=3 --dry-run=client -o yaml > my-deployment.yaml
上述命令将使用名为“192.168.11.247/web-demo/goweb-demo:20221229v3”的镜像创建一个名为“goweb-demo”的Deployment,并设置3个副本。--dry-run=client选项使kubectl只检查配置文件的语法,而不会实际创建Deployment。-o yaml选项指定输出格式为YAML,并将其重定向到my-deployment.yaml文件中。下面是我们得到的my-deployment.yaml:
apiVersion: apps/v1 kind: Deployment metadata: creationTimestamp: null labels: app: goweb-demo name: goweb-demo spec: replicas: 3 selector: matchLabels: app: goweb-demo strategy: {} template: metadata: creationTimestamp: null labels: app: goweb-demo spec: containers: - image: 192.168.11.247/web-demo/goweb-demo:20221229v3 name: goweb-demo resources: {} status: {}
编辑my-deployment.yaml文件以更改Deployment的任何其他配置选项。例如,您可以为Deployment指定标签,设置容器端口,配置健康检查等。下面是我调整后的my-deployment.yaml:
apiVersion: apps/v1 kind: Deployment metadata: name: goweb-demo spec: replicas: 3 selector: matchLabels: app: goweb template: metadata: labels: app: goweb spec: containers: - name: goweb-container image: 192.168.11.247/web-demo/goweb-demo:20221229v3
- 创建Deployment
tantianran@test-b-k8s-master:~/goweb-demo$ kubectl apply -f my-deployment.yaml deployment.apps/goweb-demo created tantianran@test-b-k8s-master:~/goweb-demo$ kubectl get deployments NAME READY UP-TO-DATE AVAILABLE AGE goweb-demo 3/3 3 3 8m25s tantianran@test-b-k8s-master:~/goweb-demo$ tantianran@test-b-k8s-master:~/goweb-demo$ kubectl get pod NAME READY STATUS RESTARTS AGE goweb-demo-654c45b968-9wcr8 1/1 Running 0 5s goweb-demo-654c45b968-jsw8z 1/1 Running 0 5s goweb-demo-654c45b968-mngq7 1/1 Running 0 5s tantianran@test-b-k8s-master:~/goweb-demo$
- 准备Service yaml配置文件 现在使用go语言开发的web demo已经跑起来了,而且跑了3个pod副本,接下来就要对外提供访问,我的goweb demo应用对外提供访问的端口是8090。
在命令行下创建一个将容器端口8090映射到Node的端口30080上的Service对象,可以使用以下命令:
kubectl create service nodeport goweb --tcp=80:8090 --node-port=30080
其中,goweb是Service对象的名称,默认也是用此名称与deployment中定义的label "app: goweb" 保持一致,--tcp=80:8090表示将容器端口8090映射到Service的端口80上,--node-port=30080表示将Service的端口30080映射到Node的端口30080上。
tantianran@test-b-k8s-master:~/goweb-demo$ kubectl get svc -o wide NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR goweb NodePort 10.111.227.27 <none> 80:30080/TCP 5s app=goweb kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 96d <none> tantianran@test-b-k8s-master:~/goweb-demo$
使用--dry-run=client -o yaml得到my-service.yaml 文件,然后使用kubectl apply命令将其应用到集群中
kubectl create service nodeport goweb --tcp=80:8090 --node-port=30080 --dry-run=client -o yaml > my-service.yaml
my-service.yaml
apiVersion: v1 kind: Service metadata: creationTimestamp: null labels: app: goweb name: goweb spec: ports: - name: 80-8090 nodePort: 30080 port: 80 protocol: TCP targetPort: 8090 selector: app: goweb type: NodePort status: loadBalancer: {}
在这个示例中,我们创建了一个名为“goweb”的服务,它将流量路由到标签为“app=goweb”的Pod上。该服务类型被设置为NodePort,并指定了端口号为30080。服务监听80端口,将流量转发到Pod上的8090端口。
- 创建service
tantianran@test-b-k8s-master:~/goweb-demo$ kubectl apply -f my-service.yaml service/goweb created tantianran@test-b-k8s-master:~/goweb-demo$ kubectl get svc -o wide NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR goweb NodePort 10.104.241.81 <none> 80:30080/TCP 7s app=goweb kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 96d <none> tantianran@test-b-k8s-master:~/goweb-demo$ kubectl get ep NAME ENDPOINTS AGE goweb 10.244.240.19:8090,10.244.240.38:8090,10.244.240.56:8090 16s kubernetes 192.168.11.13:6443 96d tantianran@test-b-k8s-master:~/goweb-demo$
要在集群外访问该服务,可以使用任何节点的IP地址和NodePort端口号。例如,如果节点的IP地址为192.168.11.14,则可以使用http://192.168.1.14:30080访问该服务。
实战开撸:案例2
在案例1中,都是使用yaml进行创建,并且分享了如何快速得到一个yaml。那么本案例2,全程在kubectl命令行下进行创建。
- 创建deployment 要创建一个名为 nginx-deployment 的 Deployment 并使用最新版本的 nginx 镜像
kubectl create deployment my-deployment001 --image=192.168.11.247/web-demo/goweb-demo:20221229v3 --replicas=3
- 暴露 Deployment 的端口
kubectl expose deployment my-deployment001 --port=80 --target-port=8090 --type=NodePort
其中,my-deployment001 是你要暴露端口的 Deployment 的名称,80 是你要使用的 Service 的端口,8090 是你要将流量路由到的 Pod 的端口,--type 是 Service 的类型,通常是 ClusterIP、NodePort 或 LoadBalancer。上面的命令中,将创建一个类型为 NodePort 的 Service,并将其暴露在随机分配的端口上。
查看Service
tantianran@test-b-k8s-master:~/goweb-demo$ kubectl get svc my-deployment001 NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE my-deployment001 NodePort 10.109.238.29 <none> 80:32537/TCP 3m48s
这将列出 Service 的详细信息,包括 Service 的 IP 地址、端口和类型,上面随机分配的端口是32537。
这样,就已经成功地创建了一个 Deployment 并将其暴露在一个端口上。现在,可以使用 Service 的 IP 地址和端口来访问应用程序。如果你使用的是 NodePort 类型的 Service,你可以在任何节点上使用 Service 的节点 IP 地址和端口来访问它。如果你使用的是 LoadBalancer 类型的 Service,Kubernetes 会在你的云提供商中自动创建一个负载均衡器,并将流量路由到你的 Service。
打开浏览器,访问看看:
最后的总结
Kubernetes (k8s) Service是一个抽象层,它为一组Pod提供了一个稳定的访问地址和DNS名称。在k8s中,Service是通过控制器和负载均衡器来实现的,它可以将流量分发给后端Pod实例,并确保它们的可用性和可靠性。下面是对Kubernetes Service的总结:
- Service类型 k8s Service有四种类型,分别是ClusterIP、NodePort、LoadBalancer和ExternalName。不同类型的Service有不同的用途,选择合适的类型非常重要。
- ClusterIP:这是最常用的类型。它为Pod提供了一个稳定的虚拟IP地址,只能从集群内部访问。
- NodePort:它为Pod提供了一个静态的端口号,可以通过任何节点的IP地址和该端口访问Service。它将请求转发到相应的Pod,支持外部访问。
- LoadBalancer:这种类型需要云服务商提供的负载均衡器支持。它为Service分配一个公共IP地址,并将流量负载均衡到Pod中。
- ExternalName:它将Service映射到一个外部地址或DNS名称,而不是选择Pod。它通常用于将k8s内部的Service与外部服务连接起来。
- Service Selector Service Selector是用来选择要将流量转发到哪个Pod的标签。每个Service都会指定一个或多个Selector,用于确定应该选择哪些Pod。在创建Service时,可以指定标签选择器以选择相关Pod。
- 端口 Service的端口指的是该Service的监听端口。Service可以监听多个端口,每个端口都可以关联一个或多个后端Pod。端口也可以分为两个类型:端口和目标端口。端口是Service监听的端口,而目标端口是后端Pod的端口。
- 负载均衡 k8s Service可以通过三种负载均衡算法来将流量分配到后端Pod中:
- Round Robin:这是最常见的负载均衡算法。它按顺序分配流量到每个Pod,然后循环下去。
- Session Affinity:这种算法会将同一客户端的所有请求都发送到同一个后端Pod中。这有助于维护状态,并确保在会话期间一致性。
- IPVS:这是一种高级的负载均衡算法,它使用Linux内核中的IPVS模块来实现流量分发。
- DNS k8s Service通过DNS来提供一个稳定的访问地址。在创建Service时,k8s会将其关联的Pod的IP地址注册到k8s集群的DNS中,并使用Service名称和Namespace作为DNS条目。这样,客户端可以通过Service名称和命名空间来访问该Service,k8s DNS将解析这个名称并将其映射到Service关联的Pod IP地址。
在k8s中,每个Pod都有一个唯一的IP地址,但是这个IP地址在Pod重新调度或者Pod数量发生变化时可能会发生变化。这种变化可能会导致客户端连接中断,因此k8s Service提供了一个稳定的访问地址,使得客户端可以通过Service名称来访问Pod而不需要关心其IP地址的变化。这种方式也使得k8s Service非常适合于微服务架构,因为它可以将多个Pod组合成一个逻辑单元,并通过一个稳定的访问地址对外提供服务。