在CSDN学Golang云原生(Kubernetes Service)

一,service的定义与基本用法

在 Kubernetes 中,Service 是一种抽象概念,用于定义一组 Pod 并为它们提供访问入口。通过 Service,您可以将多个 Pod 组合成一个逻辑单元,并使用标签选择器来确定哪些 Pod 属于该 Service。

下面是一个简单的 Service 定义示例:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: my-app # 标签选择器,用于确定哪些 Pod 属于该 Service
  ports:
    - name: http
      port: 80 # 外部暴露的端口
      targetPort: 9376 # 绑定的 Pod 端口

在上面的示例中,我们创建了一个名为 my-service 的 Service,并指定了一个标签选择器 app=my-app 来确定哪些 Pod 属于该 Service。此外,我们还指定了一个绑定端口(端口号为 80),并将其绑定到后端 Pod 的某个端口(这里为 9376)。

使用此配置文件部署该服务后,Kubernetes 将自动创建一个负载均衡器,并分配给该服务一个稳定的 IP 地址和 DNS 名称。其他应用程序可以使用这个 IP 地址或 DNS 名称来访问该服务。

需要注意的是,在 Kubernetes 中,Service 可以有不同类型:ClusterIP、NodePort、LoadBalancer 和 ExternalName。每种类型都有不同的用途和配置方式。

下面是一些常见的 Service 使用示例:

  1. ClusterIP Service:将一组 Pod 组成一个逻辑单元,并在集群内部提供访问入口。
apiVersion: v1
kind: Service
metadata:
  name: my-service-clusterip
spec:
  selector:
    app: my-app # 标签选择器,用于确定哪些 Pod 属于该 Service
  ports:
    - name: http
      port: 80 # 外部暴露的端口
      targetPort: 9376 # 绑定的 Pod 端口
  1. NodePort Service:除了提供 ClusterIP Service 的功能外,还可以在每个节点上绑定一个静态端口号,从而允许外部流量进入 Kubernetes 集群。
apiVersion: v1
kind: Service
metadata:
  name: my-service-nodeport
spec:
  selector:
    app: my-app # 标签选择器,用于确定哪些 Pod 属于该 Service
  ports:
    - name: http
      port: 80 # 外部暴露的端口(在所有节点上都会监听此端口)
      targetPort: 9376 # 绑定的 Pod 端口(Pod 内容器监听此端口)
      nodePort: 30001 # 在每个节点上绑定的静态端口号(范围为:30000-32767)
  1. LoadBalancer Service:除了提供 NodePort Service 的功能外,还可以使用云供应商提供的负载均衡器来平衡流量,从而允许外部流量进入 Kubernetes 集群。
apiVersion: v1
kind: Service
metadata:
  name: my-service-loadbalancer
spec:
  selector:
    app: my-app # 标签选择器,用于确定哪些 Pod 属于该 Service
  ports:
    - name: http
      port: 80 # 外部暴露的端口(在所有节点上都会监听此端口)
      targetPort: 9376 # 绑定的 Pod 端口(Pod 内容器监听此端口)
  type: LoadBalancer # 指定为 LoadBalancer 类型的 Service
  1. ExternalName Service:将一个服务映射到集群外部的另一个服务或域名,从而允许集群内部使用相同的 DNS 名称来访问集群外部服务。
apiVersion: v1
kind: Service
metadata:
  name: my-service-externalname
spec:
  externalName: some.api.com # 将该 Service 映射到 some.api.com 域名或 IP 地址上

这里仅列出了一些常见的示例。

二,service 4种发布类型

在 Kubernetes 中,Service 可以有不同的发布类型,常见的包括以下四种:

  1. ClusterIP:默认类型。将 Service 暴露在集群内部,并分配一个虚拟 IP 地址(Cluster IP)给该 Service。其他 Pod 和 Service 可以使用这个 IP 地址来访问该 Service。
  2. NodePort:除了提供 ClusterIP 的功能外,还会在每个节点上绑定一个静态端口号,并将流量转发到该端口号。这允许外部流量进入 Kubernetes 集群并访问该 Service。
  3. LoadBalancer:除了提供 NodePort 的功能外,还可以使用云服务提供商的负载均衡器来平衡流量。当您创建一个 LoadBalancer 类型的 Service 时,Kubernetes 会自动创建一个负载均衡器,并将其配置为将请求转发到后端 Pod 上。
  4. ExternalName:将一个服务映射到集群外部的另一个服务或域名,从而允许集群内部使用相同的 DNS 名称来访问集群外部服务。与其他类型不同,ExternalName 不需要选择任何 Pod 或 Endpoint。

需要注意的是,在进行发布之前,请确保已经创建了相关的 Deployment 或 StatefulSet 等资源,并且已经正确标记了相关的 Pod 和 Endpoint。否则,即使正确配置了发布类型和其他参数,Service 也无法正常工作。

三,service 无选择符service

在 Kubernetes 中,Service 有一个叫做选择器(selector)的属性,用于定义该 Service 所要代理的 Pod。但是有些时候我们需要将 Service 直接映射到外部 IP 或者 DNS 名称,而不是 Kubernetes 内部的 Pod,这时就可以使用无选择符(selector-less)Service。

无选择符 Service 的作用主要有两个:

  1. 将外部服务(如数据库或缓存)的访问与应用程序解耦,从而更容易地进行管理和维护。
  2. 在没有合适的标签或注释来匹配目标 Pod 的情况下,仍然可以使用 Service 进行暴露和路由。

注意:由于无选择符 Service 不涉及任何 Pod,并且不能通过 IP 地址进行流量分配,因此它只能使用 NodePort 或 LoadBalancer 类型。

四,service HeadLess Service

在 Kubernetes 中,Headless Service 是一种特殊类型的 Service,它没有 Cluster IP,也没有负载均衡器。相反,它返回一个由 Pod IP 地址组成的集合。

Headless Service 的作用是将服务发现和负载均衡交给应用程序自己来处理。这样一来,客户端可以直接连接到服务中的任何一个 Pod 上,并且不需要经过 Service 层进行代理或转发。

Headless Service 常用于以下场景:

  1. StatefulSet:StatefulSet 控制器需要为每个 Pod 分配唯一标识符和网络主机名。如果使用 ClusterIP 类型的 Service,则所有 Pod 共享同一个 DNS 名称和 IP 地址,无法满足这个需求。因此,在 StatefulSet 控制器中通常使用 Headless Service 来提供服务发现功能。
  2. 数据库集群:数据库集群通常需要使用 DNS 名称或 IP 地址来定位节点。如果使用 ClusterIP 类型的 Service,则只能将流量转发到单个节点上,不能实现负载均衡和故障恢复。因此,在数据库集群中通常使用 Headless Service 来提供服务发现功能。
  3. 自定义网络拓扑:某些场景下需要控制容器之间的网络拓扑结构,这时候就可以通过 Headless Service 将容器之间的连接直接暴露出去,并且由应用程序自己进行管理和调度。

需要注意的是,由于 Headless Service 没有 Cluster IP 和负载均衡器,所以不能使用 NodePort 或 LoadBalancer 类型。并且,在访问 Headless Service 时需要使用完整的 DNS 名称或 IP 地址来定位 Pod。

五,service 环境变量与DNS服务发现

Kubernetes中,Service是一个抽象的逻辑概念,用于定义一组后端Pod的访问方式。当创建一个Service时,Kubernetes会自动在集群内部创建一个虚拟IP(Cluster IP),并将该IP绑定到Service上。这样,在集群内部可以通过该虚拟IP来访问Service所代表的一组Pod。

对于运行在容器中的应用程序,可以通过环境变量或DNS服务发现来访问其他服务。

  1. 环境变量

当我们创建一个Service时,Kubernetes会自动为该Service中所有Pod设置一些环境变量。其中包括:

  • SERVICE_HOST:Service所绑定的虚拟IP地址。
  • SERVICE_PORT:Service所监听的端口号。

使用这些环境变量,我们就可以在容器中直接访问同一个Service中的其他Pod了。

  1. DNS服务发现

除了使用环境变量外,Kubernetes还提供了DNS服务发现机制。每个 Service 都有一个 DNS 名称,默认情况下是“servicename.namespace.svc.cluster.local”。通过DNS名称解析,就可以轻松地实现跨命名空间和跨节点的服务发现和通信。

例如,在Python代码中使用requests库调用另一个 Service:

import requests

url = "http://otherservice.default.svc.cluster.local:8080/api/v1/getdata"
response = requests.get(url)

这里,“default”是命名空间名称,“otherservice”是Service名称,“svc.cluster.local”是默认的Kubernetes集群域名。

Kubernetes中的Service提供了一种高效、灵活、可靠的服务发现和通信机制,能够满足微服务架构下各个组件之间的调用需求。

六,service TLS

在Kubernetes中,我们可以使用Service来暴露一组Pod作为一个服务。当需要对服务进行加密通信时,可以通过在Service和Pod之间添加TLS层来实现。

以下是一些步骤:

  1. 创建证书和私钥

首先,我们需要创建用于加密通信的证书和私钥。这里假设已经有了自签名证书和私钥。

  1. 创建Secret对象

然后,将证书和私钥打包到一个Kubernetes Secret对象中:

$ kubectl create secret tls mytlssecret --cert=server.crt --key=server.key

这里创建了一个名为“mytlssecret”的Secret对象,并将“server.crt”和“server.key”两个文件打包成为该对象的数据部分。

  1. 修改Service定义

接着,在Service定义中添加如下部分:

apiVersion: v1
kind: Service
metadata:
  name: myservice
spec:
  ports:
  - name: https
    port: 443
    targetPort: 80
  selector:
    app: myapp
  type: ClusterIP
  tls:
  - hosts:
    - myservice.example.com 
    secretName: mytlssecret

其中,“hosts”指定了该TLS配置所要绑定的域名,“secretName”指定了上一步创建的Secret对象名称。

  1. 更新应用程序

最后,在应用程序中更新相关代码,使其支持HTTPS协议即可。如果使用HTTP客户端库(如requests)调用其他服务时,也需要相应地修改代码以支持HTTPS协议。

需要注意的是,在使用Service TLS时,我们还需要考虑证书和私钥的管理、更新和分发等问题。可以使用工具如cert-manager来自动化这些任务,使TLS证书管理更加便捷和安全。

七,ingress http 7层路由机制

Kubernetes Ingress是一种可以将HTTP和HTTPS流量路由到集群中不同服务的API对象,通常用于实现七层(应用层)路由。

在Ingress配置中,可以定义多个规则(Rule),每个规则包含一个Host名称和若干条Path规则。对于每条Path规则,可以指定要将请求转发到哪个Service上。因此,在使用Ingress时,需要先定义好所需的Service,并将它们标记为需要通过Ingress暴露出来的服务。

Ingress主要有以下几种类型:

  1. Nginx Ingress:使用Nginx作为负载均衡器实现七层路由。
  2. Traefik Ingress:使用Traefik作为负载均衡器实现七层路由。
  3. Istio Ingress Gateway:基于Istio实现网关功能,并支持灰度发布、流量控制等高级特性。

当客户端发送请求时,Ingress会根据请求中的Host和Path信息匹配对应的规则,并将请求转发给相应的后端Service。如果没有匹配到任何规则,则会返回404错误。

总之,Kubernetes Ingress提供了一种方便易用的方式来管理应用程序的入口流量,并支持多种七层路由机制和高级特性。

八,ingress Controller 安装

安装Kubernetes Ingress Controller可以使用多种不同的方案,这里介绍一些常见的方法:

  1. 使用官方提供的Nginx Ingress Controller
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.46.0/deploy/static/provider/cloud/deploy.yaml
  1. 使用Helm安装Nginx Ingress Controller
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm install my-release ingress-nginx/ingress-nginx
  1. 使用官方提供的Traefik Ingress Controller
kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v2.4/examples/k8s/traefik-deployment.yaml
kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v2.4/examples/k8s/ui.yaml
  1. 使用Helm安装Traefik Ingress Controller
helm repo add traefik https://helm.traefik.io/traefik
helm install my-release traefik/traefik

需要注意的是,在部署Ingress Controller之前,需要确保已经正确设置了Kubernetes集群中的网络插件,并且Node节点都已经正确配置和准备好。

九,ingress转发策略配置

Kubernetes Ingress资源可以使用不同的策略来实现请求转发。这里列出一些常见的Ingress转发策略:

  1. Path-Based Routing:根据请求URL路径进行路由,可使用nginx ingress或traefik ingress实现
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: example-ingress
spec:
  rules:
  - host: example.com
    http:
      paths:
      - path: /v1
        backend:
          serviceName: service-v1
          servicePort: 80
      - path: /v2
        backend:
          serviceName: service-v2
          servicePort: 80
  1. Host-Based Routing:根据请求的主机名(host)进行路由,可使用nginx ingress或traefik ingress实现
apiVersion: networking.k8s.io/v1beta1 
kind: Ingress 
metadata:
  name: my-ingress 
spec:
  rules:
    - host: foo.bar.com 
      http:
        paths:
        - path: /path/to/service 
          backend:
            serviceName: my-service 
            servicePort : my-service-port
  1. TCP/UDP routing:将TCP/UDP流量路由到特定服务的端口,通过MetalLB等负载均衡器实现
apiVersion : v1 
kind : Service 
metadata :
   name : mysql-svc 
   labels :
     app : mysql-db   
spec :
   ports :
     - port : 3306    
       targetPort : mysql    
   selector :
     app : mysql-db  

---

apiVersion : networking.k8s.io/v1beta1 
kind : Ingress 
metadata :
   name : mysql-ingress 
spec :
   rules:
    - host: mysql.example.com
      http:
        paths:
        - path: /
          backend:
            serviceName: mysql-svc
            servicePort: 3306
  1. Fanout:将请求路由到多个服务,可使用traefik ingress实现
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: fanout-ingress
spec:
  rules:
    - host: example.com
      http:
        paths:
          - path: /serviceA/*
            backend:
              serviceName: service-a
              servicePort: 80
          - path: /serviceB/*
            backend:
              serviceName: service-b
              servicePort: 80

需要根据实际需求选择合适的Ingress转发策略。

十,ingress TLS 配置

Kubernetes Ingress可以配置TLS证书,提供HTTPS服务。下面是一个简单的Ingress TLS配置示例:

  1. 生成TLS证书和私钥
$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 
    -out /path/to/tls.crt 
    -keyout /path/to/tls.key 
    -subj "/CN=example.com"
  1. 创建k8s secret
$ kubectl create secret tls example-tls --cert=/path/to/tls.crt --key=/path/to/tls.key
  1. 配置Ingress规则
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: example-ingress
spec:
  tls:
  - hosts:
    - example.com
    secretName: example-tls #引用上一步创建的secret名称 
  rules:
  - host: example.com 
    http:
      paths:
      - path: /
        backend:
          serviceName: service-name 
          servicePort : service-port

在这个例子中,我们使用了tls字段来配置TLS证书信息。我们指定了hosts为example.com,并且将之前创建的名为example-tls的secret用于TLS证书。

需要注意的是,此处只给出了一个简单的TLS配置示例,请根据实际需求进行相应修改。同时,还需要确保您的域名和证书匹配。