• ASP.NET Core on K8S深入学习(4)你必须知道的Service


    本篇已加入《.NET Core on K8S学习实践系列文章索引》,可以点击查看更多容器化技术相关系列文章。

    前面几篇文章我们都是使用的ClusterIP供集群内部访问,每个Pod都有一个自己的IP地址,那么问题来了:当控制器使用新的Pod替代发生故障的Pod时又或者增加新的副本Pod时,新Pod会分配到新的IP地址,那么想要对外提供服务时,客户端如何找到并访问这个服务?没关系,别抠脑壳了,本文介绍的Service就是解决方案。

    一、认识Service

    1.1 什么是Service?

      Service是一个抽象概念,它定义了逻辑集合下访问Pod组的策略。通过使用Service,我们就可以不用关心这个服务下面的Pod的增加和减少、故障重启等,只需通过Service就能够访问到对应服务的容器,即通过Service来暴露Pod的资源

      这样说可能还是有点难懂,举个例子,假设我们的一个服务Service A下面有3个Pod,我们都知道Pod的IP都不是持久化的,重启之后就会有变化。那么Service B想要访问Service A的Pod,它只需跟绑定了这3个Pod的Service A打交道就可以了,无须关心下面的3个Pod的IP和端口等信息的变化。换句话说,就像一个Service Discovery服务发现的组件,你无须关心具体服务的URL,只需知道它们在服务发现中注册的Key就可以通过类似Consul、Eureka之类的服务发现组件中获取它们的URL一样,还是实现了负载均衡效果的URL。

      

    1.2 Service的几种类型

      (1)ClusterIP

       ClusterIP 服务是 Kubernetes 的默认服务。它给你一个集群内的服务,集群内的其它应用都可以访问该服务,但是集群外部无法访问它。

      因此,这种服务常被用于内部程序互相的访问,且不需要外部访问,那么这个时候用ClusterIP就比较合适,如下面的yaml文件所示:

    apiVersion: v1
    kind: Service
    metadata:  
    name: my-internal-service
    selector:    
    app: my-app
    spec:
    type: ClusterIP
    ports:  
    - name: http
    port: 80
    targetPort: 80
    protocol: TCP

      那么,如果需要从外部访问呢(比如我们在开发模式下总得调试吧)?可以启用K8S的代理模式:

    $ kubectl proxy --port=8080

      如此一来,便可以通过K8S的API来访问了,例如下面这个URL就可以访问在yaml中定义的这个my-internal-service了:

    http://localhost:8080/api/v1/proxy/namespaces/default/services/my-internal-service:http/

    PS:ClusterIP是一个虚拟IP,由K8S节点上的iptables规则管理的。iptables会将访问Service的流量转发到后端Pod,而且使用类似于轮询的负载均衡策略转发的。  

      (2)NodePort

       除了只在内部访问的服务,我们总有很多是需要暴露出来公开访问的服务吧。在ClusterIP基础上为Service在每台机器上绑定一个端口,这样就可以通过<NodeIP>:NodePort来访问这些服务。例如,下面这个yaml中定义了服务为NodePort类型:

    apiVersion: v1
    kind: Service
    metadata:  
    name: my-nodeport-service
    selector:    
    app: my-app
    spec:
    type: NodePort
    ports:  
    - name: http
    port: 80
    targetPort: 80
    nodePort: 30036
    protocol: TCP

    PS:这种方式顾名思义需要一个额外的端口来进行暴露,且端口范围只能是 30000-32767,如果节点/VM 的 IP 地址发生变化,你需要能处理这种情况。

      (3)LoadBalancer

       LoadBalancer 服务是暴露服务到 internet 的标准方式,它借助Cloud Provider创建一个外部的负载均衡器,并将请求转发到<NodeIP>:NodePort(向节点导流)。

      例如下面这个yaml中:

    kind: Service
    apiVersion: v1
    metadata:
      name: my-service
    spec:
      selector:
        app: MyApp
      ports:
      - protocol: TCP
        port: 80
        targetPort: 9376
      clusterIP: 10.0.171.239
      loadBalancerIP: 78.11.24.19
      type: LoadBalancer
    status:
      loadBalancer:
        ingress:
        - ip: 146.148.47.155

    PS:每一个用 LoadBalancer 暴露的服务都会有它自己的 IP 地址,每个用到的 LoadBalancer 都需要付费,这将是比较昂贵的花费。  

    二、Service的创建与运行

    2.1 创建Deployment

      这里仍然以我们的一个ASP.NET Core WebAPI项目为例,准备一个Deployment的YAML文件:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: edc-webapi-deployment
      namespace: aspnetcore
    spec:
      replicas: 2
      selector:
        matchLabels:
          name: edc-webapi
      template:
        metadata:
          labels:
            name: edc-webapi
        spec:
          containers:
          - name: edc-webapi-container
            image: edisonsaonian/k8s-demo
            ports:
            - containerPort: 80
            imagePullPolicy: IfNotPresent

      这里我们需要注意的就是给该Deployment标注selector的matchLabels以及template中的labels,这是一个Key/Value对,用于后续Service来匹配要挑选哪些Pod作为Service的后端,即需要给哪些Pod提供服务发现以及负载均衡的效果。

      同样,通过kubectl创建资源:

    kubectl apply -f edc-api.yaml

      然后,通过curl命令验证一下:(这里的两个IP地址是ClusterIP,它们分别位于我的两个K8S Node节点上)

    curl 10.244.1.40/api/values
    curl 10.244.2.31/api/values

      

       可以看到,我们的ASP.NET Core WebAPI正常的返回了JSON数据。

    2.2 创建Service

      接下来我们就为上面的两个Pod创建一个Service:

    apiVersion: v1
    kind: Service
    metadata:
      name: edc-webapi-service
      namespace: aspnetcore
    spec:
      ports:
        - port: 8080
          targetPort: 80
      selector:
        name: edc-webapi

      这里需要注意的几个点:

      (1)port : 8080 => 指将Service的8080端口映射到Pod的对应端口上,这里Pod的对应端口由 targetPort 指定。

      (2)selector => 指将具有 name: edc-webapi 这个label的Pod作为我们这个Service的后端,为这些Pod提供统一IP和端口。

      这里我们来进行验证一下:

    kubectl get service -n aspnetcore
    curl 10.1.59.71:8080/api/values

      

       可以看到,默认情况下Service的类型时ClusterIP,只能提供集群内部的服务访问。如果想要为外部提供访问,那么需要改为NodePort。

    2.3 使用NodePort

      下面为Service增加NodePort访问方式:

    apiVersion: v1
    kind: Service
    metadata:
      name: edc-webapi-service
      namespace: aspnetcore
    spec:
      type: NodePort
      ports:
        - port: 8080
          targetPort: 80
      selector:
        name: edc-webapi

      再次进行创建,会覆盖已有配置:

    kubectl apply -f edc-api-service.yaml

      再次进行验证,会发现已经改为了NodePort方式:

      

       这里的PORT已经变为了8080:32413,意味着它将Service中的8080端口映射到了Node节点的32413端口,我们可以通过访问Node节点的32413端口获取ASP.NET Core WebAPI返回的接口数据了。

      访问k8s-node1:

       

      访问k8s-node2:

       

    2.4 指定特定端口

      刚刚的NodePort默认情况下是随机选择一个端口(30000-32767范围内),不过我们可以使用nodePort属性指定一个特定端口:

    apiVersion: v1
    kind: Service
    metadata:
      name: edc-webapi-service
      namespace: aspnetcore
    spec:
      type: NodePort
      ports:
        - nodePort: 31000 
          port: 8080
          targetPort: 80
      selector:
        name: edc-webapi

      这里我们自己指定了一个外部访问端口:31000,通过kubectl覆盖之后,我们再次验证一下:

      访问k8s-node1:

      

       访问k8s-node2:

      

      最后,再次总结一下三个端口配置:

      (1)nodePort => Node节点上监听的端口,也就是外部访问的Service端口

      (2)port => ClusterIP上监听的端口,即内部访问的Service端口

      (3)targetPort => Pod上监听的端口,即容器内部的端口

    三、DNS访问Service

      Kubernetes默认安装了一个dns组件coredns,它位于kube-system命名空间中:

      

       每当有新的Service被创建时,coredns会添加该Service的DNS记录,于是在Cluster中的Pod便可以通过servicename.namespacename来访问Service了,从而可以做到一个服务发现的效果。

      这里我们来验证一下,通过临时创建一个busybox Pod来访问edc-webapi-service.aspnetcore:8080:

    kubectl run busybox --rm -ti --image=busybox /bin/sh

      

       可以看到,coredns组件为刚刚创建的Service edc-webapi-service创建了DNS记录,在Cluster中的Pod无须知道edc-webapi-service的IP地址只需要知道ServiceName即可访问到该Service。

    四、小结

      本文介绍了K8S中Service的基本概念及常用类型,然后通过一个具体的例子演示了如何创建Service和使用NodePort的方式对外提供访问,最后介绍了如何通过DNS的方式访问Service从而实现服务发现的效果。当然,笔者也是初学,很多东西没有介绍到,也请大家多多参考其他资料更加深入了解。

    参考资料

    (1)CloudMan,《每天5分钟玩转Kubernetes

    (2)李振良,《一天入门Kubernets教程

    (3)马哥(马永亮),《Kubernetes快速入门

    (4)小黑老,《K8S中Service的理解

  • 相关阅读:
    更新 anaconda
    spyder 每次运行前,清除上一次运行的变量
    vscode 无法使用 jupyter notebook
    vscode 关闭当前光标所在变量自动高亮
    vscode 关闭侧边栏中 git source control 的更改数目
    【java】Java组件概览(1)
    【java】字符串处理技巧记录
    【异常处理】Spring项目异常如何做异常处理
    【Springboot】Springboot学习(转)
    【微服务】微服务(转)
  • 原文地址:https://www.cnblogs.com/edisonchou/p/aspnet_core_on_k8s_deepstudy_part4.html
Copyright © 2020-2023  润新知