• 03K8S之service工作方式及使用


    service

    1.service工作模式

    1.userspace k8s1.1-
    2.iptables  k8s1.8-
    3.ipvs  k8s1.8+
    

    kubernetes中的3类IP地址

    node network(节点网络):配置在节点的接口之上
    pod network(pod 网络):配置在pod资源之上
    service network(cluster network):virtual IP,没有配置在某个接口当中,只是出现在service的规则当中。
    
    每个节点之上都有一个kube-proxy组件,它会始终监视(通过watch请求方法实现)着apiserver当中有关service资源的变动信息,当有service资源内容发生变动(创建),kube-proxy组件都将把它转化为当前节点之上的能够实现service资源调度(包括将用户请求调度到后端pod之上的规则,规则是iptables或者ipvs,取决于service的实现方式,)
    

    2.kubernetes的3种service实现模型

    1.userspace

    1. userspace: Client Pod(客户端)请求到达service以后,先把service转化为监听在某个套接字上的用户空间的kube-proxy,由它负责处理,之后再转给Service IP,service IP再转给其代理的Pod。
    对于客户端的请求,经过Service IP,还要回到监听在某个端口上的kube-proxy,由kube-proxy再进行分发,而kube-proxy是工作在用户空间的进程,这种方式就叫做userspace。但是工作效率低,其需要经过内核转给用户空间的kube-proxy进行报文封装,再次回到内核由iptables规则进行分发。
    

    2.iptables

    iptables:Client Pod(客户端)请求直接由内核iptables规则所截取,直接调度到相关联的pod。
    

    3.ipvs

    ipvs:Client Pod(客户端)请求直接由内核ipvs规则所截取,直接调度到相关联的pod。
    

    3.service使用iptables和ipvs规则实现的区别

    参考文章:https://blog.csdn.net/qq_36807862/article/details/106068871

    4.sevcie常用字段

    kubectl explain svc.spec
    selector	<map[string]string> # 选择关联的pod的标签
    ports	<[]Object> # 定义service监听端口(port),暴露外部可以访问的端口(nodePort,前提type:NodePort),以及目标端口(targetPort,)
    loadBalancerIP	<string>
    clusterIP	<string> # 手动指定集群内部访问IP,不指定此字段,默认自动随机分配IP
    type	<string> # 指定集群访问类型
    sessionAffinity # 可以设置成ClientIP,把来至同一客户端的请求调度到同一个pod中。默认是none不使用;
    
    kubectl explain svc.spec.type
    # svc类型
    ExternalName:把集群外部的服务引入到集群内部使用
    ClusterIP: 创建service时,指定集群内部通信ClusterIP。
    NodePort:接入集群外部的流量,使用NodePort
    LoadBalancer:把kubernetes部署在虚拟机上,虚拟机部署在云环境中,而云环境支持LBAS(负载均衡及服务,)的一键调用,自动在外部创建一个软负载均衡器,创建软负载均衡器时使用。
    
    kubectl explain svc.spec.ports
    ports	<[]Object>
        name	<string> # 端口名称
        port	<integer> -required- # service对外提供服务的端口
        nodePort	<integer> # type=NodePort,LoadBalancer,才能定义nodePort;service将在每个节点上暴露此端口,可以在集群外部,通过集群任意节点IP:nodePort访问此service关联的一组后端pod服务。
        protocol	<string> # 不指定的话,默认是TCP
        targetPort	<string> # 容器端口
    
    1.定义为ClusterIP时使用的ports下使用字段:
    	port: # service上的端口,k8s集群内部服务之间访问service的入口,要与镜像暴露的端口一致。
        targetPort: #可以不写, podIP上的端口 可以是端口名称,也可以是端口;如果是端口名称,要和pod中容器定义的port端口名称一致。
        
    2.定义为NodePort时使用的字段:
      type: NodePort
       ports:
       - port: # 要与镜像暴露的端口一致
         nodePort: # service对外暴露的端口
    
    3.loadbalancerIP:公有云主机底层支持创建LoadbalacerIP # 下图1
      type: LoadBalancer
      loadBalancerIP: 52.130.86.47
      ports:
      - port: 80
      selector:
        app:nginx
    4. ExternalName:集群内pod访问一个服务,此服务在集群之外,又想让pod访问到这个服务,如何做?pod网络都是内网地址,即使请求能路由出去,外部的响应报文也无法回来。
    spec:
      type: ExternalName # 下图2
      externalName: my.database.example.com # cname必须能被DNS服务解析
    

    图1:

    图2:

    5.nodePort、port、targetPort、hostPort解释

    1.nodePort

    外部流量访问k8s集群中service入口的一种方式(另一种方式是LoadBalancer),即nodeIP:nodePort是提供给外部流量访问k8s集群中service的入口。比如外部用户要访问k8s集群中的一个Web应用,那么我们可以配置对应service的type=NodePort,nodePort=30001。其他用户就可以通过浏览器http://node:30001访问到该web服务。而数据库等服务可能不需要被外界访问,只需被内部服务访问即可,那么我们就不必设置service的NodePort。
    
    apiVersion: v1
    kind: Service
    metadata:
      name: myapp 
      namespace: default
    spec:
      selector:
        app: myapp
        release: canary
      type: NodePort
      ports:
      - port: 80 # myapp svc 监听端口
        targetPort: http  # pod端口,这个名称必须是在containers.ports中有定义(containers.ports.name)
        #targetPort: 80
        nodePort: 30080
    

    2.Port

    k8s集群内部服务之间访问service的入口。即clusterIP:port是service暴露在clusterIP上的端口。mysql容器暴露了3306端口,集群内其他容器通过33306端口访问mysql服务,但是外部流量不能访问mysql服务,因为mysql服务没有配置NodePort。对应的service.yaml如下:
    
    apiVersion: v1
    kind: Service
    metadata:
      name: mysql-service
      namespace: default
    spec:
      selector:
        name: mysql-pod
      ports:
      - port: 33306
        targetPort: 3306
    

    3.targetPort

    容器的端口(最终的流量端口)。targetPort是pod上的端口,从port和nodePort上来的流量,经过kube-proxy流入到后端pod的targetPort上,最后进入容器。
    制作容器时暴露的端口一致(使用DockerFile中的EXPOSE),例如官方的nginx(参考DockerFile)暴露80端口。 对应的service.yaml如下:
    
    apiVersion: v1
    kind: Service
    metadata:
      name: nginx-service
      namespace: default
    spec:
      selector:
        name: nginx-pod
      type: NodePort  # 有配置NodePort,外部流量可访问k8s中的服务
      ports:
      - port: 30080 # 服务访问端口(service监听端口)
        targetPort: 80 # 容器端口
        nodePort: 30001 # NodePort 如果不给值,docker会随机给默认值
    

    4.hostport

    hostPort这是一种直接定义Pod网络的方式。hostPort是直接将容器的端口与所调度的节点上的端口路由,这样用户就可以通过宿主机的IP加上来访问Pod了,如:
    
    apiVersion: v1
    kind: Pod
    metadata:
      name: influxdb
    spec:
      containers:
      - name: influxdb
        image: influxdb
        ports:
        - containerPort: 8086
          hostPort: 8086
    

    5.总结

    总的来说,port和nodePort都是service的端口,前者暴露给k8s集群内部服务访问,后者暴露给k8s集群外部流量访问。从上两个端口过来的数据都需要经过反向代理kube-proxy,流入后端pod的targetPort上,最后到达pod内的容器。
    

    6.创建redis service示例

    1.创建ClusterIP类型的service:

    vim redis-svc.yaml
    apiVersion: v1
    kind: Service
    metadata:
      name: redis 
      namespace: default
    spec:
      selector:
        app: redis
        role: logstor
      # 不指定service类型,默认创建在集群内部使用的service,不手动指定ClusterIP,会随机分配一个10.96.0.0/12网络的IP,如果手动指定,一定要确认这个IP没被分配,不和原有的service冲突。
      clusterIP: 10.97.97.97  # 一旦被创建成功,无法再次apply修改。除非删除svc重建。
      type: ClusterIP
      ports:
      - port: 6379
        # targetPort: redis # 
        targetPort: 6379
    

    redis deployment:

    [root@master01 service]# cat ../controll/pod-daemonset-controll.yaml 
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: redis
      namespace: default
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: redis
          role: logstor
      template:
        metadata:
          labels:
            app: redis
            role: logstor
        spec:
          containers:
          - name: redis
            image: redis:6.0.3
            ports: 
            - name: redis
              containerPort: 6379
    
    当一个service创建完成以后,会自动在集群的DNS中动态添加一个A记录,我们可以通过这个服务名进行解析,格式为:
    	SVC_NAME>NS_NAME_DOMAIN.LTD.
    	集群默认的域名后缀:
        	svc.cluster.local.
         
        redis.default.svc.cluster.local. # 对于redis service的域名
    

    2.创建NodePort类型的service:

    apiVersion: v1
    kind: Service
    metadata:
      name: myapp 
      namespace: default
    spec:
      selector:
        app: myapp
        release: canary
      # 不指定service类型,默认创建在集群内部使用的service,不手动指定ClusterIP,会随机分配一个10.96.0.0/12网络的IP,如果手动指定,一定要确认这个IP没被分配,不和原有的service冲突。
      clusterIP: 10.99.99.99 # 自定义集群内部service IP
      type: NodePort
      ports:
      - port: 80 # myapp svc 监听端口
        targetPort: http  # pod端口,这个名称必须是在containers.ports中有定义(containers.ports.name)
        #targetPort: 80
        nodePort: 30080
    

    myapp deployment:

    [root@master01 service]# cat ../controll/pod-deploy-controll.yaml 
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: myapp-deploy-controll
      namespace: default
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: myapp
          release: canary
      template:
        metadata:
          name: myapp-deploy-controll
          labels:
            app: myapp
            release: canary
        spec:
          containers:
          - name: myapp
            image: nginx:1.20.2
            ports:
            - name: http
              containerPort: 80
    

    7.使用ipvs模型的配置补充

    编辑kubelet配置文件/etc/sysconfig/kubelet,设置其忽略Swap启用的状态错误,内容如下:
    	KUBE_EXTRA_ARGS="--fail-swap-on=false"
    	KUBE_PROXY_MODE=ipvs 
    # 安装ipvs调度算法相关模块
    yum intall ip_vs,ip_vs_rr,ip_vs_wrr,ip_vs_sh,nf_conntrack_ipv45
    

    HeadLess Service

    有时不需要或不想要负载均衡,以及单独的 Service IP。 遇到这种情况,可以通过指定 Cluster IP(spec.clusterIP)的值为 "None" 来创建 Headless Service。您可以使用headless Service 与其他服务发现机制进行接口,而不必与 Kubernetes 的实现捆绑在一起。典型应用就是Ingress。
    
    vim headless-svc.yaml
    apiVersion: v1
    kind: Service
    metadata:
      name:  headless-svc 
      namespace: default
    spec:
      selector:
        app: myapp
        release: canary
      clusterIP: None
      ports:
      - port: 80
        targetPort: 80
    
    kubectl apply -f headless-svc.yaml 
    kubectl get svc -o wide
    

    dig -t A headless-svc.default.svc.cluster.local. @10.96.0.10
    

    dig -t A myapp.default.svc.cluster.local. @10.96.0.10
    

  • 相关阅读:
    Verilog设计Valid-Ready握手协议
    E203 CSR rtl实现分析
    E203 CSR寄存器
    RiscV汇编介绍(1)-编译过程
    RiscV汇编介绍(2)-编译过程
    博客迁移通知
    Visual Studio中的环境变量(以Visual Studio 2013为例)
    Android Studio搜索功能(查找功能)及快捷键图文详解
    《更好的解释(数学篇)》——后序
    《更好的解释(数学篇)》——第十二章
  • 原文地址:https://www.cnblogs.com/zhangchaocoming/p/15648064.html
Copyright © 2020-2023  润新知