k8s指南-Service

目录:
(1)k8s指南-概述
(2)k8s指南-架构
(3)k8s指南-工作负载(1)
(4)k8s指南-工作负载(2)
(5)k8s指南-工作负载(3)
(6)k8s指南-工作负载(4)
(7)k8s指南-Service
(8)k8s指南-Ingress
(9)k8s指南-DNS与服务发现
(10)K8S指南-平滑升级与自动扩缩容


在k8s集群中,虽然每个pod都会被分配一个单独的ip地址,但由于pod是有生命周期的,一旦pod被销毁,其对应的ip地址就会消失。如果在某地方需要用到这个ip,那就会出问题。Service就是用来解决这个问题的。

在k8s中,Service是一种抽象概念,它定义了一组逻辑pod和访问这些pod的策略。Service所拥有的pod集合通常是由选择器来定义的。

实际上,k8s中的service概念和我们通常提到的微服务中的服务是一样的。只不过k8s中的service是一种具体资源。

每个Service都有一个集群ip,表示服务对外的ip地址,所有访问该服务的网络请求直接访问这个ip地址,然后由service将其转发到服务对应的实际pods中的某一个。

Service与DNS一起实现K8S中的服务发现,Service与Ingress一起实现K8S中的负载均衡,这也是Service的两个主要作用

定义服务

Kubernetes中的Service是一个REST对象,类似于pod。像所有的REST对象一样,可以通过POST方法将服务定义发过API服务器来创建新的实例。
下面是一个示例:

apiVersiono: v1
kind: Service
metadata:
    name : my-service
spec:
     selector:
	   app.kubernetes.io/name: MyApp
     ports:
	   - protocol: TCP
	   port: 80
	   targetPort: 9376

以上文件会创建一个服务叫my-service,该服务可以将请求转发到服务对应的某个pod的9376端口。

Pod中的端口定义是有名字的,你可以在service的targetPort属性中引用这些名称。如下所示:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    app.kubernetes.io/name: proxy
spec:
  containers:
  - name: nginx
    image: nginx:stable
    ports:
      - containerPort: 80
        name: http-web-svc

---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app.kubernetes.io/name: proxy
  ports:
  - name: name-of-service-port
    protocol: TCP
    port: 80
    targetPort: http-web-svc

服务的默认协议是TCP,你还可以使用任何其他受支持的协议,如UDP或者SCTP等。

Kubernetes在服务对象上也支持多个端口定义,每个端口定义可以具有相同的protocol,也可以具有不同的protocol。

没有选择符的Service

由于选择符的存在,服务最常见的用法是为k8s pod的访问提供抽象,但是当与相应的EndpointSlices对象一起使用且没有选择算符时,服务也可以为其他类型的后端提供抽象,包括在集群外运行的后端。例如:

  • 希望在生产环境中使用外部的数据库集群,但在测试环境使用自己的数据库。
  • 希望服务指向另一个命名空间或其他集群中的服务。

在这些场景中,你可以定义没有选择符的Service,如:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376

由于此服务没有选择符,因此不会自动创建相应的EndpointSlice对象。你可以通过手动添加EndpointSlice对象,将服务手动映射到运行该服务的网络地址和端口上:

apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
  name: my-service-1 # 按惯例将服务的名称用作 EndpointSlice 名称的前缀
  labels:
    # 你应设置 "kubernetes.io/service-name" 标签。
    # 设置其值以匹配服务的名称
    kubernetes.io/service-name: my-service
addressType: IPv4
ports:
  - name: '' # 留空,因为 port 9376 未被 IANA 分配为已注册端口
    appProtocol: http
    protocol: TCP
    port: 9376
endpoints:
  - addresses:
      - "10.4.5.6" # 此列表中的 IP 地址可以按任何顺序显示
      - "10.1.2.3"

多端口service

对于某些服务,你需要公开多个端口。Kubernetes允许你在Service对象上配置多个端口定义。为服务使用多个端口时,必须提供所有端口名称,以便它们无歧义。如:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app.kubernetes.io/name: MyApp
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 9376
    - name: https
      protocol: TCP
      port: 443
      targetPort: 9377

与一般的Kubernetes名称一样,端口名称只能包含小写字母,数字,字符和 -。端口名称必须以字母数字字符开头和结尾。

选择自己的ip地址

在Service创建的请求中,可以通过设置spec.clusterIP字段来指定自己的集群IP地址的,比如,希望替换一个已经存在的DNS条目,或者遗留系统已经配置了一个固定的IP且很难重新配置。

用户选择的ip地址必须合法,并且这个IP地址在service-cluster-ip-range CIDR范围内,如果ip地址不合法,API服务器会返回422错误码。

服务发现

Kubernetes支持两种基本的服务发现模式 – 环境变量和DNS。

环境变量

当Pod运行在node上时,kubelet会为每个活跃的Pod添加一组环境变量: {SVCNAME}_SERVICE_HOST{SVCNAME}_SERVICE_PORT。注意这里的Service的名称需大写,横线被转成下划线。

启动前文的nginx-deployment,然后进入其中一个pod,查看环境变量,可以看到如下结果:

root@nginx-deployment-7fb96c846b-66rwr:/# env | grep SERVICE     
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_SERVICE_PORT=443
KUBERNETES_SERVICE_HOST=10.96.0.1

系统把当前default空间中的kubernetes本身的服务host和port都添加到当前pod中了。

如果先创建客户端pod,再创建服务端service,此时客户端pod不会设定service的host和port到客户端pod中去。换句话说,想通过环境变量的方式去做服务发现,则必须先创建service,再生成客户端pod。而使用DNS查到服务的集群IP,则不用考虑此问题。

DNS
你可以使用附加组件为Kubernetes集群设置DNS服务。DNS服务器(如CoreDNS)监视Kubernetes API中的新服务,并为每个服务创建一组DNS记录。
如果在整个集群中都启用DNS,则所有pod都应该能够通过其DNS名称自动解析服务。

Headless Services

有时不需要负载均衡和单独的Service IP,在这种情况下,可以通过指定Cluster IP的值为"None"来创建Headless Service。

对于无头Services并不会分配Cluster IP,kube-proxy 不会处理它们,并且平台也不会为它们进行负载均衡和路由。DNS如何实现自动配置,依赖于Service是否定义了选择算符。

带选择符的服务
对定义了选择算符的无头服务,Kubernetes控制平面在Kuberntes API中创建EndpointSlice对象,并且修改DNS配置返回A或者AAAA记录(IPv4或IPv6地址),通过此地址直接到达Service对应的后端pod上。

无选择符的服务
对没有选择符的无头服务,控制平面不会创建EndpointSlice对象,然而DNS系统会查找和配置以下之一:

  • 对于type: ExternalName服务,查找和配置其CNAME记录。
  • 对于其他类型的服务,针对Service的就绪端点的所有IP地址,查找和配置DNS A/AAAA记录:对于IPv4端点,DNS系统创建A条记录;对于IPv6端点,创建AAAA条记录。

发布服务

对一些应用的某些部分,可能希望将其暴露给kubernetes集群外部的ip地址。Kubernetes的serviceTypes允许你指定所需要的Service类型。
Type的取值以及行为如下:

  • ClusterIP:通过集群内部IP暴露服务,选择该值时服务只能够在集群内部访问。这也是type的默认值。
  • NodePort:通过每个节点上的IP和静态端口(NodePort)暴露服务。为了让节点端口可用,Kubernetes设置了集群IP地址,这等同于你请求type:ClusterIP的服务。
  • LoadBalancer:使用云提供商的负载均衡器向外部暴露服务。外部负载均衡器可以将流量路由到自动创建的NodePort服务和ClusterIP服务上。
  • ExternalName:通过返回CNAME记录和对应值,可以将服务映射到externalName字段的内容(如foo.bar.example.com)。无需创建任何类型代理。

NodePort类型

如果你将type字段设置为NodePort,则kubernetes控制平面将在--service-node-port-range标志指定的范围内分配端口(默认值:30000-32767)。每个节点将那个端口代理到你的服务中,你的服务在其.spec.ports[*].nodePort字段中报告已分配的端口。

使用NodePort可以让你自由设置自己的负载均衡解决方案,配置Kubernetes不完全支持的环境,甚至直接暴露一个或多个节点的IP地址。

对于NodePort服务,Kubernetes会额外分配一个端口(TCP、UDP或SCTP以匹配服务的协议)。集群中每个节点都将自动监听分配的端口并将流量转发到与该服务关联的某个就绪端点。通过使用适当的协议和适当的端口连接到所有节点,你将能够从集群外部使用NodePort类型的服务。

以下是一个NodePort类型的服务,它指定了一个NodePort值30007。

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  type: NodePort
  selector:
    app.kubernetes.io/name: MyApp
  ports:
      # 默认情况下,为了方便起见,`targetPort` 被设置为与 `port` 字段相同的值。
    - port: 80
      targetPort: 80
      # 可选字段
      # 默认情况下,为了方便起见,Kubernetes 控制平面会从某个范围内分配一个端口号(默认:30000-32767)
      nodePort: 30007

LoadBalancer类型

在使用支持外部负载均衡器的云提供商的服务时,设置 type 的值为 “LoadBalancer”, 将为 Service 提供负载均衡器。 负载均衡器是异步创建的,关于被提供的负载均衡器的信息将会通过 Service 的 status.loadBalancer 字段发布出去。示例如下:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app.kubernetes.io/name: MyApp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376
  clusterIP: 10.0.171.239
  type: LoadBalancer
status:
  loadBalancer:
    ingress:
    - ip: 192.0.2.127

来自外部负载均衡器的流量将直接重定向到后端 Pod 上,不过实际它们是如何工作的,这要依赖于云提供商。

某些云提供商允许设置 loadBalancerIP。 在这些情况下,将根据用户设置的 loadBalancerIP 来创建负载均衡器。 如果没有设置 loadBalancerIP 字段,将会给负载均衡器指派一个临时 IP。 如果设置了 loadBalancerIP,但云提供商并不支持这种特性,那么设置的 loadBalancerIP 值将会被忽略掉。

要实现 type: LoadBalancer 的服务,Kubernetes 通常首先进行与请求 type: NodePort 服务等效的更改。 cloud-controller-manager 组件然后配置外部负载均衡器以将流量转发到已分配的节点端口。

作为 Alpha 特性,你可以将负载均衡服务配置为忽略分配节点端口, 前提是云提供商实现支持这点。

参考资料

[1]. https://kubernetes.io/zh-cn/docs/concepts/services-networking/service/#type-nodeport

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值