关于kubernetes:五分钟k8s入门到实战跨服务调用

43次阅读

共计 3131 个字符,预计需要花费 8 分钟才能阅读完成。

背景

在做传统业务开发的时候,当咱们的服务提供方有多个实例时,往往咱们须要将对方的服务列表保留在本地,而后采纳肯定的算法进行调用;当服务提供方的列表变动时还得及时告诉调用方。

student:  
   url:     
   - 192.168.1.1:8081     
   - 192.168.1.2:8081

这样天然是对单方都带来不少的累赘,所以后续推出的服务调用框架都会想方法解决这个问题。

spring cloud 为例:

服务提供方会向一个服务注册核心注册本人的服务(名称、IP 等信息),客户端每次调用的时候会向服务注册核心获取一个节点信息,而后发动调用。

但当咱们切换到 k8s 后,这些基础设施都交给了 k8s 解决了,所以 k8s 天然得有一个组件来解决服务注册和调用的问题。

也就是咱们明天重点介绍的 service

service

在介绍 service 之前我先调整了源码:

func main() {http.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) {name, _ := os.Hostname()  
      log.Printf("%s ping", name)  
      fmt.Fprint(w, "pong")  
   })  
   http.HandleFunc("/service", func(w http.ResponseWriter, r *http.Request) {resp, err := http.Get("http://k8s-combat-service:8081/ping")  
      if err != nil {log.Println(err)  
         fmt.Fprint(w, err)  
         return  
      }  
      fmt.Fprint(w, resp.Status)  
   })  
  
   http.ListenAndServe(":8081", nil)  
}

新增了一个 /service 的接口,这个接口会通过 service 的形式调用服务提供者的服务,而后从新打包。

make docker

同时也新增了一个 deployment-service.yaml:

apiVersion: apps/v1  
kind: Deployment  
metadata:  
  labels:  
    app: k8s-combat-service # 通过标签抉择关联  
  name: k8s-combat-service  
spec:  
  replicas: 1  
  selector:  
    matchLabels:  
      app: k8s-combat-service  
  template:  
    metadata:  
      labels:  
        app: k8s-combat-service  
    spec:  
      containers:  
        - name: k8s-combat-service  
          image: crossoverjie/k8s-combat:v1  
          imagePullPolicy: Always  
          resources:  
            limits:  
              cpu: "1"  
              memory: 100Mi  
            requests:  
              cpu: "0.1"  
              memory: 10Mi  
---  
apiVersion: v1  
kind: Service  
metadata:  
  name: k8s-combat-service  
spec:  
  selector:  
    app: k8s-combat-service # 通过标签抉择关联  
  type: ClusterIP  
  ports:  
    - port: 8081        # 本 Service 的端口  
      targetPort: 8081  # 容器端口  
      name: app

应用雷同的镜像部署一个新的 deployment,名称为 k8s-combat-service,重点是新增了一个kind: Service 的对象。

这个就是用于申明 service 的组件,在这个组件中也是应用 selector 标签和 deployment 进行了关联。

也就是说这个 service 用于服务于名称等于 k8s-combat-servicedeployment

上面的两个端口也很好了解,一个是代理的端口,另一个是 service 本身提供进来的端口。

至于 type: ClusterIP 是用于申明不同类型的 service,除此之外的类型还有:

  • NodePort
  • LoadBalancer
  • ExternalName
    等类型,默认是 ClusterIP,当初不必纠结这几种类型的作用,后续咱们在讲到 Ingress 的时候会具体介绍。

负载测试

咱们先别离将这两个 deployment 部署好:

k apply -f deployment/deployment.yaml
k apply -f deployment/deployment-service.yaml

❯ k get pod
NAME                                  READY   STATUS    RESTARTS   AGE
k8s-combat-7867bfb596-67p5m           1/1     Running   0          3h22m
k8s-combat-service-5b77f59bf7-zpqwt   1/1     Running   0          3h22m

因为我新增了一个 /service 的接口,用于在 k8s-combat 中通过 service 调用 k8s-combat-service 的接口。

resp, err := http.Get("http://k8s-combat-service:8081/ping")

其中 k8s-combat-service 服务的域名就是他的服务名称。

如果是跨 namespace 调用时,须要指定一个残缺名称,在后续的章节会演示。

咱们整个的调用流程如下:

置信大家也看得出来绝对于 spring cloud 这类微服务框架提供的客户端负载形式,service 是一种服务端负载,有点相似于 Nginx 的反向代理。

为了更直观的验证这个流程,此时我将 k8s-combat-service 的正本数减少到 2:

spec:  
  replicas: 2

只须要再次执行:

❯ k apply -f deployment/deployment-service.yaml
deployment.apps/k8s-combat-service configured
service/k8s-combat-service unchanged

不论咱们对 deployment 的做了什么变更,都只须要 apply 这个 yaml 文件即可,k8s 会主动将以后的 deployment 调整为咱们预期的状态(比方这里的正本数量减少为 2);这也就是 k8s 中常说的 申明式 API

能够看到此时 k8s-combat-service 的正本数曾经变为两个了。
如果咱们此时查看这个 service 的形容时:

❯ k describe svc k8s-combat-service |grep Endpoints
Endpoints:         192.168.130.133:8081,192.168.130.29:8081

会发现它曾经代理了这两个 Pod 的 IP。

此时我进入了 k8s-combat-7867bfb596-67p5m 的容器:

k exec -it k8s-combat-7867bfb596-67p5m bash
curl http://127.0.0.1:8081/service

并执行两次 /service 接口,发现申请会轮训进入 k8s-combat-service 的代理的 IP 中。

因为 k8s service 是基于 TCP/UDP 的四层负载,所以在 http1.1 中是能够做到申请级的负载平衡,但如果是相似于 gRPC 这类长链接就无奈做到申请级的负载平衡。

换句话说 service 只反对连贯级别的负载。

如果要反对 gRPC,就得应用 Istio 这类服务网格,相干内容会在后续章节详解。

总结

总的来说 k8s service 提供了繁难的服务注册发现和负载平衡性能,当咱们只提供 http 服务时是齐全够用的。

相干的源码和 yaml 资源文件都存在这里:
https://github.com/crossoverJie/k8s-combat

正文完
 0