不背锅运维:粗讲:K8S的Service及分享现撸案例

2023-03-08 08:31:07 浏览数 (3)

Service存在的意义

Kubernetes中的Service是一种网络抽象,用于将一组Pod暴露给其他组件,例如其他Pod或外部用户。Service可以作为一个负载均衡器,为一组Pod提供单一的IP地址和DNS名称,并通过选择器来将流量路由到这些Pod。

Services的存在有以下几个意义:

  1. 透明的服务发现:  Kubernetes使用Service作为一种透明的服务发现机制。使用Service可以将Pod隐藏在后面,这样其他组件可以使用Service的DNS名称来访问它们,而不需要知道Pod的实际IP地址和端口号。
  2. 负载均衡:  Service可以将流量路由到一组Pod上,并使用标签选择器将流量均匀地分配给这些Pod。这使得可以轻松地进行水平扩展,以满足不断增长的负载。
  3. 稳定的IP地址:  Kubernetes为每个Service分配一个稳定的IP地址,这个IP地址与Pod的生命周期无关。这意味着可以在Pod启动和停止时保持稳定的服务地址,并且无需手动更改任何配置。
  4. 外部访问:  通过将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

代码语言:txt复制
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的三种访问类型:

  1. ClusterIP:默认的访问类型,将创建一个虚拟IP地址,代表一组后端Pod。只能从集群内部访问该Service,外部无法访问。
  2. NodePort:将在每个Node上公开一个端口,并将该端口重定向到Service。可以通过Node的IP地址和该端口访问该Service。可以从集群外部访问该Service,但需要在防火墙中打开该端口。
  3. 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

  1. 准备Deployment yaml配置文件
代码语言:txt复制
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:

代码语言:txt复制
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:

代码语言:txt复制
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
  1. 创建Deployment
代码语言:txt复制
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$ 
  1. 准备Service yaml配置文件 现在使用go语言开发的web demo已经跑起来了,而且跑了3个pod副本,接下来就要对外提供访问,我的goweb demo应用对外提供访问的端口是8090。

在命令行下创建一个将容器端口8090映射到Node的端口30080上的Service对象,可以使用以下命令:

代码语言:txt复制
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上。

代码语言:txt复制
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命令将其应用到集群中

代码语言:txt复制
kubectl create service nodeport goweb --tcp=80:8090 --node-port=30080 --dry-run=client -o yaml > my-service.yaml 

my-service.yaml

代码语言:txt复制
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端口。

  1. 创建service
代码语言:txt复制
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命令行下进行创建。

  1. 创建deployment 要创建一个名为 nginx-deployment 的 Deployment 并使用最新版本的 nginx 镜像
代码语言:txt复制
kubectl create deployment my-deployment001 --image=192.168.11.247/web-demo/goweb-demo:20221229v3 --replicas=3
  1. 暴露 Deployment 的端口
代码语言:txt复制
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

代码语言:txt复制
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的总结:

  1. 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与外部服务连接起来。
  1. Service Selector Service Selector是用来选择要将流量转发到哪个Pod的标签。每个Service都会指定一个或多个Selector,用于确定应该选择哪些Pod。在创建Service时,可以指定标签选择器以选择相关Pod。
  2. 端口 Service的端口指的是该Service的监听端口。Service可以监听多个端口,每个端口都可以关联一个或多个后端Pod。端口也可以分为两个类型:端口和目标端口。端口是Service监听的端口,而目标端口是后端Pod的端口。
  3. 负载均衡 k8s Service可以通过三种负载均衡算法来将流量分配到后端Pod中:
  • Round Robin:这是最常见的负载均衡算法。它按顺序分配流量到每个Pod,然后循环下去。
  • Session Affinity:这种算法会将同一客户端的所有请求都发送到同一个后端Pod中。这有助于维护状态,并确保在会话期间一致性。
  • IPVS:这是一种高级的负载均衡算法,它使用Linux内核中的IPVS模块来实现流量分发。
  1. 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组合成一个逻辑单元,并通过一个稳定的访问地址对外提供服务。

本文转载于(喜欢的盆友关注我们):https://mp.weixin.qq.com/s/9HBcSLkcxLZ8dA-0kqtLcA

0 人点赞