Kubernetes资源对象service

著作:行癫 <盗版必究> ------ ## 一:Service ​ 将运行在一组 [Pods](https://v1-23.docs.kubernetes.io/docs/concepts/workloads/pods/pod-overview/) 上的应用程序公开为网络服务的抽象方法 ​ 使用 Kubernetes,你无需修改应用程序即可使用不熟悉的服务发现机制;Kubernetes 为 Pods 提供自己的 IP 地址,并为一组 Pod 提供相同的 DNS 名, 并且可以在它们之间进行负载均衡 ​ Kubernetes Service 定义了这样一种抽象:逻辑上的一组 Pod,一种可以访问它们的策略 —— 通常称为微服务 ​ 举个例子,考虑一个图片处理后端,它运行了 3 个副本。这些副本是可互换的 —— 前端不需要关心它们调用了哪个后端副本。 然而组成这一组后端程序的 Pod 实际上可能会发生变化, 前端客户端不应该也没必要知道,而且也不需要跟踪这一组后端的状态 #### 1.定义 Service 例如,假定有一组 Pod,它们对外暴露了 9376 端口,同时还被打上 `app=MyApp` 标签: ```shell apiVersion: v1 kind: Service metadata: name: my-service spec: selector: app: MyApp ports: - protocol: TCP port: 80 targetPort: 9376 ``` 上述配置创建一个名称为 "my-service" 的 Service 对象,它会将请求代理到使用 TCP 端口 9376,并且具有标签 `"app=MyApp"` 的 Pod 上 Kubernetes 为该服务分配一个 IP 地址(有时称为 "集群IP"),该 IP 地址由服务代理使用 注意: ​ Service 能够将一个接收 `port` 映射到任意的 `targetPort`。 默认情况下,`targetPort` 将被设置为与 `port` 字段相同的值 #### 2.多端口 Service ​ 对于某些服务,你需要公开多个端口。 Kubernetes 允许你在 Service 对象上配置多个端口定义 ```shell apiVersion: v1 kind: Service metadata: name: my-service spec: selector: app: MyApp ports: - name: http protocol: TCP port: 80 targetPort: 9376 - name: https protocol: TCP port: 443 targetPort: 9377 ``` ## 二:发布服务 #### 1.服务类型 ClusterIP NodePort LoadBalancer ExternalName #### 2.服务类型 ​ 对一些应用的某些部分(如前端),可能希望将其暴露给 Kubernetes 集群外部 的 IP 地址 ​ Kubernetes `ServiceTypes` 允许指定你所需要的 Service 类型,默认是 `ClusterIP` `Type` 的取值以及行为如下: ​ `ClusterIP`:通过集群的内部 IP 暴露服务,选择该值时服务只能够在集群内部访问。 这也是默认的 `ServiceType` ![img](https://xingdian-image.oss-cn-beijing.aliyuncs.com/xingdian-image/6R1zaHS1QM_i4c4W1k2ttg.png) ​ `NodePort`:通过每个节点上的 IP 和静态端口(`NodePort`)暴露服务。 `NodePort` 服务会路由到自动创建的 `ClusterIP` 服务。 通过请求 `<节点 IP>:<节点端口>`,你可以从集群的外部访问一个 `NodePort` 服务 ![img](https://xingdian-image.oss-cn-beijing.aliyuncs.com/xingdian-image/-E5GOvNElgId7mwjBs9elw.png) ​ [`LoadBalancer`](https://v1-23.docs.kubernetes.io/zh/docs/concepts/services-networking/service/#loadbalancer):使用云提供商的负载均衡器向外部暴露服务。 外部负载均衡器可以将流量路由到自动创建的 `NodePort` 服务和 `ClusterIP` 服务上 ​ 你也可以使用Ingress来暴露自己的服务。 Ingress 不是一种服务类型,但它充当集群的入口点。 它可以将路由规则整合到一个资源中,因为它可以在同一IP地址下公开多个服务 ```shell [root@master nginx]# kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer ``` #### 3.NodePort ​ 如果你将 `type` 字段设置为 `NodePort`,则 Kubernetes 控制平面将在 `--service-node-port-range` 标志指定的范围内分配端口(默认值:30000-32767) 例如: ```shell apiVersion: v1 kind: Service metadata: name: my-service spec: type: NodePort selector: app: MyApp ports: # 默认情况下,为了方便起见,`targetPort` 被设置为与 `port` 字段相同的值。 - port: 80 targetPort: 80 # 可选字段 # 默认情况下,为了方便起见,Kubernetes 控制平面会从某个范围内分配一个端口号(默认:30000-32767) nodePort: 30007 ``` #### 4.案例 ```shell apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx-server image: nginx:1.16 ports: - containerPort: 80 ``` ```shell apiVersion: v1 kind: Service metadata: name: nginx-services labels: app: nginx spec: type: NodePort ports: - port: 88 targetPort: 80 nodePort: 30010 selector: app: nginx ``` #### 5.了解 ​ `ExternalName` 是 `Kubernetes` 服务(`Service`)类型中的一种,它允许你将服务映射到一个外部的 DNS 名称,而不是选择器(`selector`)所定义的一组 Pod;这意味着当你在集群内部通过服务名称访问时,实际上是在访问外部指定的资源。 使用场景 ​ `ExternalName` 类型的服务非常适合以下几种情况: ​ 当你需要将内部服务指向外部系统或第三方 API ​ 当你希望服务名称和外部资源名称之间保持解耦,即使外部资源发生变化,只需要更新服务配置 ​ 对于微服务架构中的跨团队合作,不同团队管理自己的服务,通过 `ExternalName` 来互相调用对方的服务 配置方式 ​ 创建一个 `ExternalName` 类型的服务非常简单,只需在服务定义文件中设置 `spec.type` 为 `ExternalName` 并提供 `spec.externalName` 字段来指明你要映射的外部域名 ```yaml apiVersion: v1 kind: Service metadata: name: external-service namespace: default spec: type: ExternalName externalName: example.com ``` 案例 ​ 假设你正在管理一个电子商务平台,该平台由多个微服务组成,并且有一个专门处理支付的外部服务,这个支付服务是由第三方提供商托管的,其域名是 `payments.externalprovider.com` 背景 ​ 你的电商平台需要调用支付网关来完成交易过程。支付网关是一个由外部供应商提供的服务,不在你的 `Kubernetes`集群内运行,但是你的应用程序代码需要能够像调用内部服务一样方便地访问它 使用 `ExternalName` 服务 ​ 为了简化与外部支付服务的交互,你可以创建一个名为 payment-gateway 的 ExternalName 类型的服务,这样所有的内部服务就可以通过 payment-gateway.default.svc.cluster.local(假设在默认命名空间中)来访问外部的支付服务,而不需要直接硬编码外部域名 ```yaml apiVersion: v1 kind: Service metadata: name: payment-gateway namespace: default spec: type: ExternalName externalName: payments.externalprovider.com ``` 应用程序代码调整 ​ 在你的应用程序代码中,你只需要配置服务名称为 payment-gateway 或者根据集群内的 DNS 解析规则使用完整的 FQDN (Fully Qualified Domain Name) payment-gateway.default.svc.cluster.local 来发起请求。比如,在 Java Spring Boot 应用中,你可以设置 REST 客户端的基础 URL: ```java @Bean public RestTemplate restTemplate(RestTemplateBuilder builder) { // 注意这里使用的是服务名称,而不是直接使用外部域名 return builder.rootUri("http://payment-gateway").build(); } ``` 总结 ​ 通过这种方式,`ExternalName` 服务帮助你在`Kubernetes` 环境中优雅地整合了外部依赖,同时保持了良好的抽象层次和灵活性